约战Angular中Promise(1)

来源:互联网 发布:如何隐藏mac下方菜单 编辑:程序博客网 时间:2024/04/20 00:10

在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内部的事件轮询机制,我们先且看下回详细分解。。。

0 0
原创粉丝点击