资讯专栏INFORMATION COLUMN

AngularJS中$q的promise使用及链式调用传值问题

hiyayiji / 2947人阅读

摘要:规范中文是提供的一个服务。实际调用这个方法最终在此处加入到队列中定义此处调用进入此处是链式调用传参关键,实际是上一个的的返回值,所以能知道,如果需要所有的都能取到异步任务的返回值,就得在的函数中,将值返回。

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);
      }
    }
  }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79554.html

相关文章

  • Angular $q 完全指南

    摘要:假设家具厂在一周后做完了这个衣柜,并如约送到了张先生家包邮哦,亲,这就叫做衣柜,也就是已解决。这样,整个异步流程就圆满完成,无论成功或者失败,张先生都没有往里面投入任何额外的时间成本。 如果想使用 $http 或者其他异步操作, 那 $q 是必须要掌握的概念啦. Lets get started! 如何理解$q, deferred object ? 形象的讲解angular中的$q与p...

    U2FsdGVkX1x 评论0 收藏0
  • promise/deferred 模式原理分析和实现

    摘要:三模式模式其实包含两部分和。六化在编码的时候,想要用进行异步操作流程控制,就要将当前的异步回调函数封装成。 一、什么是promise/deferred 模式 promise/deferred 模式是,根据promise/A 或者它的增强修改版promise/A+ 规范 实现的promise异步操作的一种实现方式。 异步的广度使用使得回调,嵌套出现,但是一但出现深度的嵌套,就会让codi...

    gclove 评论0 收藏0
  • AngularJS 使用 Promise

    摘要:如何在中使用要在中使用要使用的内置服务。用来拒绝可以为字符串对象等。获取的执行状态然后使用这个函数来传递它。无论是成功了还是失败了当结果可用之后都会立即异步调用或者在被执行或者拒绝之前可能会被调用到多次以提供过程状态的提示。 如何在 AngularJS 中使用 Promise 要在 AngularJS 中使用 Promise, 要使用 AngularJS 的内置服务 $q。 我们可以...

    voidking 评论0 收藏0
  • Q.js几种创建promise对象方法对比

    摘要:的意思是,从字面意思来看是用了的方法,继承原有的方法类,然后又添加了自己的某些私有方法。用来实现代码如下的意思是,从字面意思来看是用了的方法。 世界上最远的距离不是生与死的距离,而是文档就在你面前,你依然不知道这个库怎么用。 鄙人IQ不高,已经被Q.js虐了几天。查看了github上kriskowal/q的文档,现在把几种看明白了的使用方法整理记录下来,以下几种方法可以把nodejs中...

    fsmStudy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<