zoukankan      html  css  js  c++  java
  • $q in Angular [ngdoc service] 翻译

    promise / deferred 实现的灵感来自于 [Kris Kowal's Q][1] - [The CommonJS Promise proposal][2] (CommonJS Promise建议文档)描述了将 promise 作为一个接口,用来与异步执行操作 (action) 的结果对象进行交互,该操作 (action) 在给定时间内可能或不可能完成(如超时,错误,拦截等等)。

    从错误处理的角度看,deferredpromise APIs 对于异步编程, 等同于同步编程的 trycatch 以及throw 关键字.

    // 在本例中,假设 `$q`, `scope` 以及 `okToGreet` 在当前执行环境中是可用的
    // (如它们已经被注入,或者作为参数传递进来).
    function asyncGreet(name) {
        var deferred = $q.defer();
        setTimeout(function () {
            deferred.notify('About to greet ' + name + '.');
            if (okToGreet(name)) {
                deferred.resolve('Hello, ' + name + '!');
            } else {
                deferred.reject('Greeting ' + name + ' is not allowed.');
            }
        }, 1000);
        return deferred.promise;
    }
    var promise = asyncGreet('Robin Hood');
    promise.then(function (greeting) {
        alert('Success: ' + greeting);
    }, function (reason) {
        alert('Failed: ' + reason);
    }, function (update) {
        alert('Got notification: ' + update);
    });
    

    一开始,引人这种额外的复杂性,其效果可能是不明显的。 当执行顺序按照 promisedeferred APIs 确定的那样,其优点就显现出来了。请参考: [https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md][3]

    另外 promise api 可以实现在传统的回调([CPS][4])方法中难以实现的组合方式。 更多信息请查阅 [Q文档][5] ,尤其是 [串行与并行结合promises][6] 的章节。

    Deferred API

    通过调用 $q.defer() 可以构造一个新的 deffered 实例。

    deffered 对象是将 Promise 实例与 可以用来标记任务状态(执行是否成功)的 APIs 相关联。

    deffered 对象的方法

    • resolve(value) —— 传入 value 解决派生的 promise。 如果 value 是一个通过 $q.reject 构造的拒绝对象(rejection) , 该 promise 将被拒绝。
    • reject(reason) —— 拒绝派生的 promise,并给出原因。这相当于通过 $q.reject 构造的拒绝对象(rejection) 作为参数传递给 resolve
    • notify(value) —— 在 promise 执行的过程中提供状态更新。这在 promise 被解决或拒绝之前可能会被多次调用。

    deffered 对象的属性

    • promise{Promise} —— 与延迟(deferred)相关联的 promise 对象。

    Promise API

    当创建 deferred 实例时会创建一个新的 promise 对象,并可以通过 deferred.promise 得到该引用。
    promise 对象的目的是在 deferred 任务完成时,允许感兴趣的部分取得其执行结果。

    promise 对象的方法

    • then(successCallback, errorCallback, notifyCallback) —— 不管 promise 是被处理还是被拒绝, 一旦结果(the result)可用,then 就会尽快地异步调用. 回调函数被调用时会传递进一个参数: 结果(the result)或者拒绝的理由(reject reason)。此外,在 promise 被 reslove 或 reject 之前, notify 回调可能被调用 0 到多次,以提供一个进度的指示。
      这个方法会返回一个新的 promise 对象,该对象根据 successCallbackerrorCallback 的返回值表示是被 resolved 或 rejected 。 它还通过 notifyCallback 方法的返回值进行通知。promise 不能从 notifyCallback 方法得知是被 resloved 还是 rejected.
    • catch(errorCallback) —— promise.then(null, errorCallback) 的快捷方式.
    • finally(callback) —— 让你可以观察到一个 promise 是被执行还是被拒绝,但这样做不允许修改最后的 value 值。 这可以用来做一些释放资源或者清理无用对象的工作,不管 promise 是被 resolved 还是rejected. 更多的信息[请参阅完整文档规范][7].
      因为在 ES3 版本的 JavaScript 中 finally 是一个保留字,不能作为属性名,所以为了兼容 IE8 与 Andriod 2.x, 需要借助 promise['finally'](callback) 这种形式来调用该方法。

    Chaining promises | 创建promise链

    因为调用一个 promisethen 方法返回一个新的派生 promise 实例,所以创建 promises链 也是很容易的:

    promiseB = promiseA.then(function(result) {
        return result + 1;
    });
    
    // promiseB 将会在处理完 promiseA 之后立即被处理,
    // 并且其 value 值是 promiseA 的结果增加 1
    

    我们可以创建任意长度的 promise链;因为一个 promise 可以被另一个 promise处理(进一步推迟解决完成时间),所以在 promise链 上的任意一点进行阻塞/延迟(pause/defer)都是可行的。这使得实现如 $http 响应拦截器这样功能强大的 APIs 成为现实.

    Kris Kowal's Q 与 $q 之间的区别

    主要区别有两点:
    Angular中的 $q 集成了 {@link ng.(rootScope.Scope} `Scope` 模型观察机制,这意味着解决或拒绝的结果会以更快地传播速度反映在数据模型中(model),避免不必要的浏览器重绘,因为重绘会导致UI闪烁. `Q` 比 `)q 拥有更多的功能特性,但也带来了代码字节数的增加。$q` 虽然是轻量级的,但包含了一般的异步任务所需的所有重要功能。

    it('should simulate promise', inject(function($q, $rootScope) {
      var deferred = $q.defer();
      var promise = deferred.promise;
      var resolvedValue;
    
      promise.then(function(value) { resolvedValue = value; });
      expect(resolvedValue).toBeUndefined();
    
      // 模拟 promise 的 resolving
      deferred.resolve(123);
      // 注意 'then' function 不是同步调用的.
      // 因为我们需要 promise API 一直是异步的(async),
      // 不管是在同步调用还是异步调用中都是如此.
      expect(resolvedValue).toBeUndefined();
    
      // 使用 $apply()将 promise resolution 传递到 'then' functions .
      $rootScope.$apply();
      expect(resolvedValue).toEqual(123);
    }));
    

    Dependencies

    $rootScope

    Methods

    • $q# defer()
      创建一个 递延(Deferred)对象 表示一个将来要完成任务.
      返回 {Deferred} 返回一个新实例的 Deferred.

    • $q# reject(reason)
      创建一个被特定的原因 rejected 的 promise. 此 api 应该用于在一个 promises链 中进行转发(?) rejection。如果你正在处理 promise链 中的最后一个 promise,你就不用担心它。
      deferreds/promises 与我们熟悉的的 try/catch/throw 行为进行对比,可以认为 reject 相当于 JavaScript 中的 throw 关键字。这也意味着如果你通过一个 promiseerror 回调,"catch" 了一个错误,而且你想要从当前的 promise 中转发这个 error 到派生的 promise 中,就必须通过返回的 rejection(由 reject 构造的),重新抛出(rethrow)这个 error

    promiseB = promiseA.then(function(result) {
      // success: 此处可以执行某些操作,然后直接使用原有的result,
      // 或者对result进行操作,来处理接下来的promiseB
      return result;
    }, function(reason) {
      // error: handle the error if possible and
      //        resolve promiseB with newPromiseOrValue,
      //        否则转向拒绝 promiseB 的分支
      if (canHandle(reason)) {
       // 处理错误和恢复
       return newPromiseOrValue;
      }
      return $q.reject(reason);
    });
    

    参数: reason
    类型: *
    描述: Constant, message, exception 或代表拒绝原因的 object。
    返回: Promise 返回一个promise ,已经因为 reason 而被拒绝了 。

    • when(value)
      将一个对象(可能是value 或 [第三方]then-able promise) 包装为一个 $q promise。 这在你不确定所处理的对象是否是一个promise 时是很有用的,有可能该对象来自于一个不被信任的源头。
      参数: value
      类型: *
      描述: promise 的值
      返回 Promise 根据传入的值/或promise 返回一个包装后的 promise

    • all(promises)
      合并多个 promises 为单个 promise,在所有输入的 promise 都处理之后,组合之后的 promise 才会处理完成。
      参数: promises
      类型: Array./Object.
      描述: promises的数组或者引用
      返回: Promise 返回单个的 promise,将与一个数组解决/散列值, 每个值对应于在相同的索引/关键的承诺 承诺 /散列数组。 如果任何承诺解决排斥,这产生的承诺将被拒绝 拒绝相同的值。

  • 相关阅读:
    回溯算法(DFS:深度优先)
    KNN原理和实现
    Anaconda虚拟环境控制
    c++容器
    最坏情况为线性时间的选择算法
    JVM原理解析
    substr、substring和slice的区别
    word-wrap与break-word属性的区别
    js修改伪类的值
    快速批量删除文件名中相同的文字
  • 原文地址:https://www.cnblogs.com/shih/p/6826776.html
Copyright © 2011-2022 走看看