后一个任务等待前一个任务结束再执行。程序执行顺序与任务排列顺序一致的,同步的。javascript
参考:php
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.htmlhtml
https://segmentfault.com/q/1010000000140970java
在JavaScript中,回调函数具体的定义为:函数A做为参数(函数引用)传递到另外一个函数B中,而且这个函数B执行函数A。咱们就说函数A叫作回调函数。若是没有名称(函数表达式),就叫作匿名回调函数。jquery
所以callback 不必定用于异步,通常同步(阻塞)的场景下也常常用到回调,好比要求执行某些操做后执行回调函数。ajax
var func1=function(callback){ //do something. (callback && typeof(callback) === "function") && callback(); } var func2=function(){} func1(func2);
function f1(callback){ setTimeout(function () { // f1的任务代码 callback(); }, 1000); } f1(f2)
采用这种方式,咱们把同步操做变成了异步操做,f1不会堵塞程序运行,至关于先执行程序的主要逻辑,将耗时的操做推迟执行。编程
回调函数的优势是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,并且每一个任务只能指定一个回调函数。segmentfault
异步回调的例子:api
$(document).ready(callback); $.ajax({ url: "test.html", context: document.body }).done(function() { $(this).addClass("done"); }).fail(function() { alert("error"); }).always(function() { alert("complete"); }); /** 注意的是,ajax请求确实是异步的,不过这请求是由浏览器新开一个线程请求,当请求的状态变动时,若是先前已设置回调,这异步线程就产生状态变动事件放到 JavaScript引擎的处理队列中等待处理。见:http://www.phpv.net/html/1700.html */
回调何时执行promise
回调函数,通常在同步情境下是最后执行的,而在异步情境下有可能不执行,由于事件没有被触发或者条件不知足。
回调函数的使用场合
回调函数的传递
上面说了,要将函数引用或者函数表达式做为参数传递。
$.get('myhtmlpage.html', myCallBack);//这是对的 $.get('myhtmlpage.html', myCallBack('foo', 'bar'));//这是错的,那么要带参数呢? $.get('myhtmlpage.html', function(){//带参数的使用函数表达式 myCallBack('foo', 'bar'); });
另外,最好保证回调存在且必须是函数引用或者函数表达式:
(callback && typeof(callback) === "function") && callback();
事件监听:
var doc = $(document); function f2(){ console.log("done"); } function f1(){ setTimeout(function(){ doc.trigger("done") }, 1000); } doc.on("done", f2); f1();
发布订阅:和事件监听如出一辙啊。
观察者模式所作的工做就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另外一边的变化。
var Observable = {//doc callbacks: [], add: function(fn) { this.callbacks.push(fn); }, fire: function() { this.callbacks.forEach(function(fn) { fn(); }) } } Observable.add(function() { alert(1) }) Observable.add(function() { alert(2) }) Observable.fire(); // 1, 2
Promises对象是CommonJS工做组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每个异步任务返回一个Promise对象,该对象有一个then方法,容许指定回调函数。好比,f1的回调函数f2,能够写成:
f1().then(f2);
f1要进行以下改写(这里使用的是jQuery的实现):
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
dfd.resolve();
}, 500);
return dfd.promise;
}
这样写的优势在于,回调函数变成了链式写法,程序的流程能够看得很清楚,并且有一整套的配套方法,能够实现许多强大的功能。
好比,指定多个回调函数:
f1().then(f2).then(f3);
再好比,指定发生错误时的回调函数:
f1().then(f2).fail(f3);
并且,它还有一个前面三种方法都没有的好处:若是一个任务已经完成,再添加回调函数,该回调函数会当即执行。因此,你不用担忧是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。