promise是什么

这里不解释promise是什么,因为我相信你来看文章的时候已经知道你什么是promise了。
此处有promise规范。

Promise/A+规范 中文
Promise/A+
ES2016:MDN Promise

$q

  • $q是AngularJS提供的一个服务。

  • $q是跟AngularJS的$rootScope模板集成的,所以在AngularJS中执行和拒绝都很快。(编辑器疯了,dollar符号就是打不出来,就叫 'dollar'q)

  • $q是跟AngularJS模板引擎集成的,这意味着在视图中找到任何Promise都会在视图中被执行或者拒绝。

如何在AngularJS中使用

直接上栗子,程序员都不喜欢听你废话~〒▽〒

        var app = angular.module('app', [])
            .controller('testController', function ($scope, $q) {
                //定义一个defer
                var defer = $q.defer();
                var promise = defer.promise;
                promise.then(function (data) {
                    //成功后的逻辑处理
                }, function (error) {
                    //失败后的逻辑处理
                });
                //模拟通过--实际应该是一个异步的callback中调用
                defer.resolve('[data]');
                //模拟拒绝--实际应该是一个异步的callback中调用
                defer.reject('[data]');
            });

链式调用

then会返回一个新的promise对象,所以直接jQuery风格的链式调用。
还是直接上栗子:

        var app = angular.module('app', [])
            .controller('testController', function ($scope, $q) {
                //定义一个defer
                var defer = $q.defer();
                var promise = defer.promise;
                promise.then(function () {
                    console.log('then-resolved-1');
                }, function () {
                    console.log('then-rejected-1');
                })
                .then(function () {
                    console.log('then-resolved-2');
                }, function () {
                    console.log('then-rejected-2');
                });
                //模拟通过--实际应该是一个异步的callback中调用
                defer.resolve('[data]');
                //模拟拒绝--实际应该是一个异步的callback中调用
                defer.reject('[data]');
            });

来看下是如何实现链式调用的,下面是AngularJS源码实现:

//angular.js
  Promise.prototype = {
    then: function(onFulfilled, onRejected, progressBack) {
      var result = new Deferred();//此处可以看出,每个then都会返回一个新的Deferred对象。

      this.$$state.pending = this.$$state.pending || [];
      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);

      return result.promise;
    },
    //其他省略
    ...
    }
//Deferred定义
  function Deferred() {
    this.promise = new Promise();//可以看到defer的promise对象是一个new Promise()
    //Necessary to support unbound execution :/
    this.resolve = simpleBind(this, this.resolve);
    this.reject = simpleBind(this, this.reject);
    this.notify = simpleBind(this, this.notify);
  }

链式调用参数传递

看过上面链式调用的栗子和AngularJS的源码后,大家就能知道每个then的上下文其实是不一样的,因为每次都是新new 出来的Promise对象。
先给栗子:

    var app = angular.module('app', [])
        .controller('testController', function ($scope, $q) {
            //定义一个defer
            var defer = $q.defer();
            var promise = defer.promise;
            promise.then(function (data) {
                //...
                return data;// data = 1
            }, function (error) {
                //...
            })
            .then(function (data) {
                //...
                return data;//data = 1
            }, function (error) {
                //...
            });
            //模拟通过--实际应该是一个异步的callback中调用
            defer.resolve('1');
        });

接下来看一段源码解析,看看AngularJS是如何调用Promise的。

//angular.js
 Deferred.prototype = {
    resolve: function(val) {
      if (this.promise.$$state.status) return;
      if (val === this.promise) {
        this.$$reject($qMinErr(
          'qcycle',
          "Expected promise to be resolved with value other than itself '{0}'",
          val));
      }
      else {
        this.$$resolve(val);//实际调用这个方法
      }

    },

    $$resolve: function(val) {
      var then, fns;

      fns = callOnce(this, this.$$resolve, this.$$reject);
      try {
        if ((isObject(val) || isFunction(val))) then = val && val.then;
        if (isFunction(then)) {
          this.promise.$$state.status = -1;
          then.call(val, fns[0], fns[1], this.notify);
        } else {
          this.promise.$$state.value = val;
          this.promise.$$state.status = 1;
          scheduleProcessQueue(this.promise.$$state);//最终在此处加入到队列中
        }
      } catch (e) {
        fns[1](e);
        exceptionHandler(e);
      }
    },...
    
    //scheduleProcessQueue定义
   function scheduleProcessQueue(state) {
    if (state.processScheduled || !state.pending) return;
    state.processScheduled = true;
    nextTick(function() { processQueue(state); });//此处调用进入processQueue
  }

 function processQueue(state) {
    var fn, promise, pending;

    pending = state.pending;
    state.processScheduled = false;
    state.pending = undefined;
    for (var i = 0, ii = pending.length; i < ii; ++i) {
      promise = pending[i][0];
      fn = pending[i][state.status];
      try {
        if (isFunction(fn)) {
          promise.resolve(fn(state.value));//此处是链式调用传参关键,fn(state.value)实际是上一个then的resolve的返回值,所以能知道,如果需要所有的then都能取到异步任务的返回值,就得在then的resolve函数中,将值返回。
        } else if (state.status === 1) {
          promise.resolve(state.value);
        } else {
          promise.reject(state.value);
        }
      } catch (e) {
        promise.reject(e);
        exceptionHandler(e);
      }
    }
  }

咸鱼爱吃梨
170 声望5 粉丝