Javascript 的Promise 和 Deferred对像 第1部分:理论

在看angularjs 和 dojo中文档时总会看到Promise 和 Deferred,今天在google 在找到两篇关于这方面的文章。

介绍

不久以前,Javascript 程序员来处理异步事件时主要使用回调函数。

回调函数是一段执行代码,作为参数传递给另外一段执行函数,在适合的时候执行,而不是在调用时立即执行 - Wikipedie

也就是说, 一个函数可以作为参数传递给另外一个函数,当另外一个函数被调用时,它开始执行。

在回调函数内部没有任何错误, 但根据其环境,我们在编写程序时有更多的方法来管理异步事件, 在这里我们的目标要测试一组可用的方法:promise 对像和 deferred对像。 在第一部分,我们将讲理论和语法,在第二部分讲解实际使用。


在Javascript 有效使用异步事件的关键是理解程序的继续执行(获得想要的值继续执行),即使在进行中没有获得想要的值(出现网络错误或者其它)也能继续执行相应代码。  在Javascript异步事件中处理还未完成的任务(还在请求,不知道会返回什么值)的值非常有挑战 -  特别是当你第一次开始时。

最经典的例子是 XMLHttpRequest( Ajax), 想像下你想做的:

  • 创建一个 ajax 请求,来获得一些数据
  • 立刻用这些数据来做某件事件 然后
  • 做另外一件事件
在我们的程序中,先初始化一个Ajax 请求。 提出请求后不像同步事件那样暂停运行,而是继续执行。 等到我们从Ajax request 获得响应数据,整个应用程序都完成了运行。

承诺(Promises) & 延迟(Deferreds): 是什么?

Promises是一种编辑结构,1976以来一直存在。 简而言之:
  • 承诺代表一个还末知的值
  • 延迟代表还末完成的任务
从一个更高水平考虑, 在Javascript中的承诺让我们可以以同步的方式来输写异步代码。 

Javascript 的Promise 和 Deferred对像 第1部分:理论_第1张图片

Promise/A 

Promise/A 建议了以下标准行为但没有规定API实现的细节. 

一个Promise:
  • 代表单次完成操作返回的最终值
  • 可以是以下3种状态之一: 未实现的,实现的 和 失败的。 仅允许 未实现状态到实现状态或者失败状态。
  • 具有一个函数作为属性 then的值。 then会返回一个promise.
  • 为了在承诺结束时,需要添加 fulfilledHanlder, errorHandler和progressHandler。
  • 从回调处理函数返回的值是返回的承诺的fulfillment值。
  • 承诺的值不准被改变(避免监听器创建意外行为时产生副作用)
换句话说,不管这些细微的差别:

一个Promise(承诺)充当一个末来值的代理, 它有3种可能的状态,并且需要添一个函数, 这个函数添加了多个处理器来处理它的状态:fulfilledHandler, errorHandler 和progressHandler(可选) 并且当处理器执行完毕后会返回一个被解析或者被拒绝的Promise.

状态和承诺返回值

一个承诺可能含有3种状态: unfulfilled, fulfilled 和 failed.
  • unfulfilled: 由于一个承诺是未知值的代理,所以它开始时为 unfulfilled 状态。
  • fulfilled: 承诺被它想要的值填充
  • failed: 如果承诺被返回为一个异常, 则为 failed状态。
一个承诺只能从unfulfilled 到 fulfilled或者 failed.  根据解决(获得想要的值)或者拒决 状态, 任何观察者会被通知并且将promise/value的值传递给观察者。 一旦 promise已被解析(获得值)或者 被拒绝,状态和结果者都不能在修改。

这里有一个例子:
// Promise to be filled with future value
var futureValue = new Promise();

// .then() will return a new promise
var anotherFutureValue = futureValue.then();

// Promise state handlers ( must be a function ).
// The returned value of the fulfilled / failed handler will be the value of the promise.
futureValue.then({

    // Called if/when the promise is fulfilled
    fulfilledHandler: function() {},

    // Called if/when the promise fails
    errorHandler: function() {},

    // Called for progress events (not all implementations of promises have this)
    progressHandler: function() {}
});

不同的实现和性能

当选择一个promise库时, 有一些事项里需要考虑。 并非所有的实现都是一样的, 它们在提供的API工具,性能, 行为都有不同。

由于Promise/A 标准 仅是一个promises 行为的概括。 而没有实现的细节。 不同的pormise库有不同的功能集。 所有遵循 Promise/A标准的库都有 .then()函数, 但它们的API还是不同。 另外, 它们依然可以彼此交换promises(一个库中的承诺可在另一个库里使用)。  jQuery比较例外,因为它没有完全实现Promise/A. 关于它的决定可以查看 文档 和 讨论. 在 jQuery实现一个未捕获异常来停止程序的运行。  由于不同的实现, 它跟实现了Promise/A标准的库一起工作时就会出现问题。

一个解决方案就是将jQuery的承诺转化到遵循 Promise/A 的库。 然后在使用遵循 Promise/A 的API

例如:
when($.ajax()).then()

当全部阅读完整篇关于jQuery决定依然采用自己的promise.  一提到性能就是激起了我的好奇心。 我决定做一个快速的性能测试, 我使用了Benchmark.js 和 测试创建的结果 并且解析了一个 deferred对像。 

以下是结果:

jQuery 91.6kb When.js 1.04kb Q.js 8.74kb
9,979 ops/sec ±10.22% 96,225 ops/sec ±10.10% 2,385 ops/sec ±3.42%
注:通过 Closure Compiler压缩,但没有gzipped过。

在运行完它们的测试,我从 深入测试promise 库的文章里发现了相似的结果。

不同的性能在真实的应用里微不足道。但在我的Benchmark.js测试中, when.js 以明显优势胜出。 

除了大小和性能,显然还有其它的考虑。 应该使用哪个库,还取决于你特定的情况和项目的需要。 以下是一些库的概述:

  • when.js :快速, 轻量的实现, 包含许多有用的工具。 在2.0版本完全支持异步解决方案。
  • Q.js: 可以在浏览器和 Node.js上运行。 提供了一个强键的API, 完全遵循 Promise/A。
  • RSVP:  裸机实现,完全支持Promise/A。
  • jQuery: 不遵循Pomise/A, 但被广泛使用。 如果你已经在项目中使用了jQuery, 它很容易上手。 值得看看。

总结

承诺为Javascript开发者提供了一个处理异步事件的工具。 现在我们已经讲了promise对像和 deferred对像的细节以及表现。 我们准备进一步来看看如何使用它们。 在第二部分, 我们将近距离的使用Promises,  一些常见的问题和Jquery API实现的细节。 

资源:

  • Promise/A+

你可能感兴趣的:(JavaScript,JavaScript,Promise,deferred,承诺与延迟)