在angular出现之前,web开发中前端跟后台的交互采用xhr的ajax技术,即xhr的异步请求,异步肯定就不能阻塞当前的线程,所以这个时候回调就非常重要,在commonJS中曾定义过promise规范,即一个异步请求函数把一个耗时操作请求提交出去,可以马上获得返回值,这个返回值就是传说中的promise,说到promise,有一个很重要的方法就是then()方法,这个方法一般会有两个参数,分别为resolve,reject,这两个一般为function对象,作为完成时的回调方法,要实现回调,事件机制是非常有必要的,在nodeJS中,是底层基于event Loop的事件轮询实现可怕的io回调金字塔,所以在angular中,就让异步轮询队列(就是AsyncQueue)来在ng中来担任这个重要角色。
ng中promise的实现主要靠一个$q
服务,这个service由$QProvider
的$get()
构造,这个函数主要调用qFactory函数对Q进行构造,q服务是ng实现promise的一个关键服务,首先它有一个重要的方法defer(),这是个含有多个闭包的方法,主要是构造一个promise发生器(我暂时这么称呼它),里面含有resolve(),reject(),还有多出来的一个notify()工具方法,这些方法都是未来的then()回调方法,最重要的是,这个defered对象还有一个promise的对象属性,所谓的then()就定义在promise里面了,我们先来看看promise里面的then方法:
then: function(callback, errback, progressback) {
var result = defer();
var wrappedCallback = function(value) {
try {
result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
} catch(e) {
result.reject(e);
exceptionHandler(e);
}
};
var wrappedErrback = function(reason) {
try {
result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
} catch(e) {
result.reject(e);
exceptionHandler(e);
}
};
var wrappedProgressback = function(progress) {
try {
result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
} catch(e) {
exceptionHandler(e);
}
};
if (pending) {
pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
} else {
value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
}
return result.promise;
},
"catch": function(callback) {
return this.then(null, callback);
}
在这段代码中我们直接看then()方法其实就定义了三个方法,wrappedCallback (),wrappedErrback (),wrappedProgressback (),其实这三个方法都是对应resolve(),reject(),notify()三个方法,这三个方法主要的任务就是对我们then()里面的三个参数(在ng中有个神奇的地方就是不仅有成功和错误的回调处理,还可以触发notify事件,监听任务处理的进度)进行判断(比如是否为function对象),鉴于三个函数有异曲同工之妙,我就只来分析第一个就好了,首先在then()的开始,通过defer()构造出来一个defe对象
var result = defer();
因为要调用这个对象的三个处理方法,所以需要得到一个defer对象,然后then()需要检查当前回调的情况,即查看pending的值,如果当前回调金字塔还没有结束,即当前回调的结果还是一个promise,即链式的then()调用(在nodeJS等中经常使用的回调金字塔转换为then()调用链),然后then()就把三个传进来的参数(这三个参数就是我们用户自定义的各种情形处理的回调函数),进行封装,然后把它们push进等待队列进行等候,如下:
if (pending) {
pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
} else {
value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
}
return result.promise;
可以看到最后then()return回来的还是一个promise类型,这就为then()的链式调用提供结构基础。
然而then()这么给我们定义的三个回调做这么一层封装到底有什么作用呢,看看在封装中then()主要干了什么:
try {
result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
} catch(e) {
result.reject(e);
exceptionHandler(e);
}
};
上面的result就是实现通过defer()构造的对象,可以看到,如果这个封装的回调方法被执行到,就会借用defer对象的一个工具方法resolve(),这个函数主要的作用就是成功时对我们函数执行结果进行分析(里面可以看到我们的Callback已经被调用了),下面进入这个函数代码:
resolve: function(val) {
if (pending) {
var callbacks = pending;
pending = undefined;
value = ref(val);
if (callbacks.length) {
nextTick(function() {
var callback;
for (var i = 0, ii = callbacks.length; i < ii; i++) {
callback = callbacks[i];
value.then(callback[0], callback[1], callback[2]);
}
});
}
}
}
首先是一个判断,如果当前回调链已经空了,即不是一个pending状态,就说明then()已经执行到尽头了,本次处理到此就可以收工,如果还在pending状态,那么就开始取then()调用链的下一个元素了,这里就有一个比较复杂的地方了,就是涉及到then()调用链的变化以及关联的等待队列的一个变化,以及nextTick()函数调用道德ng内部的事件轮询机制,我们先且看下回详细分解。。。