html5中文学习网

您的位置: 首页 > 网站及特效实例 > javascript特效 » 正文

理解JavaScript中Promise的使用_javascript技巧_

[ ] 已经帮助:人解决问题

Javascript 采用回调函数(callback)来处理异步编程。从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doom),绝对是一种糟糕的编程体验。于是便有了 CommonJS 的 Promises/A 规范,用于解决回调金字塔问题。本文先介绍 Promises 相关规范,然后再通过解读一个迷你的 Promises 以加深理解。XGSHTML5中文学习网 - HTML5先行者学习网

什么是 PromiseXGSHTML5中文学习网 - HTML5先行者学习网
一个 Promise 对象代表一个目前还不可用,但是在未来的某个时间点可以被解析的值。它允许你以一种同步的方式编写异步代码。例如,如果你想要使用 Promise API 异步调用一个远程的服务器,你需要创建一个代表数据将会在未来由 Web 服务返回的 Promise 对象。唯一的问题是目前数据还不可用。当请求完成并从服务器返回时数据将变为可用数据。在此期间,Promise 对象将扮演一个真实数据的代理角色。接下来,你可以在 Promise 对象上绑定一个回调函数,一旦真实数据变得可用这个回调函数将会被调用。XGSHTML5中文学习网 - HTML5先行者学习网

Promise 对象曾经以多种形式存在于许多语言中。XGSHTML5中文学习网 - HTML5先行者学习网

去除厄运的回调金字塔(Pyramid of Doom)XGSHTML5中文学习网 - HTML5先行者学习网
Javascript 中最常见的反模式做法是回调内部再嵌套回调。XGSHTML5中文学习网 - HTML5先行者学习网

// 回调金字塔asyncOperation(function(data){ // 处理 `data` anotherAsync(function(data2){   // 处理 `data2`   yetAnotherAsync(function(){     // 完成   }); });});

引入 Promises 之后的代码XGSHTML5中文学习网 - HTML5先行者学习网

promiseSomething().then(function(data){  // 处理 `data`  return anotherAsync();}).then(function(data2){  // 处理 `data2`  return yetAnotherAsync();}).then(function(){  // 完成});

Promises 将嵌套的 callback,改造成一系列的.then的连缀调用,去除了层层缩进的糟糕代码风格。Promises 不是一种解决具体问题的算法,而已一种更好的代码组织模式。接受新的组织模式同时,也逐渐以全新的视角来理解异步调用。XGSHTML5中文学习网 - HTML5先行者学习网

各个语言平台都有相应的 Promise 实现XGSHTML5中文学习网 - HTML5先行者学习网

  • Java's java.util.concurrent.FutureXGSHTML5中文学习网 - HTML5先行者学习网
  • Python's Twisted deferreds and PEP-3148 futuresXGSHTML5中文学习网 - HTML5先行者学习网
  • F#'s AsyncXGSHTML5中文学习网 - HTML5先行者学习网
  • .Net's TaskXGSHTML5中文学习网 - HTML5先行者学习网
  • C++ 11's std::futureXGSHTML5中文学习网 - HTML5先行者学习网
  • Dart's FutureXGSHTML5中文学习网 - HTML5先行者学习网
  • Javascript's Promises/A/B/D/A+XGSHTML5中文学习网 - HTML5先行者学习网

下面我来相信了解一下 javascript 语言环境下各个规范的一些细节。XGSHTML5中文学习网 - HTML5先行者学习网

Promises/A 规范XGSHTML5中文学习网 - HTML5先行者学习网
promise 表示一个最终值,该值由一个操作完成时返回。XGSHTML5中文学习网 - HTML5先行者学习网

  • promise 有三种状态:**未完成** (unfulfilled),**完成** (fulfilled) 和**失败** (failed)。XGSHTML5中文学习网 - HTML5先行者学习网
  • promise 的状态只能由**未完成**转换成完成,或者**未完成**转换成**失败** 。XGSHTML5中文学习网 - HTML5先行者学习网
  • promise 的状态转换只发生一次。XGSHTML5中文学习网 - HTML5先行者学习网

promise 有一个 then 方法,then 方法可以接受 3 个函数作为参数。前两个函数对应 promise 的两种状态 fulfilled 和 rejected 的回调函数。第三个函数用于处理进度信息(对进度回调的支持是可选的)。XGSHTML5中文学习网 - HTML5先行者学习网

promiseSomething().then(function(fulfilled){    //当promise状态变成fulfilled时,调用此函数  },function(rejected){    //当promise状态变成rejected时,调用此函数  },function(progress){    //当返回进度信息时,调用此函数  });

如果 promise 支持如下连个附加方法,称之为可交互的 promiseXGSHTML5中文学习网 - HTML5先行者学习网

  • get(propertyName)

获得当前 promise 最终值上的一个属性,返回值是一个新的 promise。XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

  • call(functionName, arg1, arg2, ...)

调用当然 promise 最终值上的一个方法,返回值也是一个新的promise。XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

Promises/B 规范XGSHTML5中文学习网 - HTML5先行者学习网
在 Promises/A 的基础上,Promises/B 定义了一组 promise 模块需要实现的 APIXGSHTML5中文学习网 - HTML5先行者学习网

when(value, callback, errback_opt)XGSHTML5中文学习网 - HTML5先行者学习网
如果 value 不是一个 promise ,那么下一事件循环callback会被调用,value 作为 callback 的传入值。如果 value 是一个 promise,promise 的状态已经完成或者变成完成时,那么下一事件循环 callback 会被调用,resolve 的值会被传入 callback;promise 的状态已经失败或者变成失败时,那么下一事件循环 errback 会被调用,reason 会作为失败的理由传入 errback。XGSHTML5中文学习网 - HTML5先行者学习网

asap(value, callback, errback_opt)XGSHTML5中文学习网 - HTML5先行者学习网
与 when 最大的区别,如果 value 不是一个 promise,会被立即执行,不会等到下一事件循环。XGSHTML5中文学习网 - HTML5先行者学习网

enqueue(task Function)XGSHTML5中文学习网 - HTML5先行者学习网
尽可能快地在接下来的事件循环调用 task 方法。XGSHTML5中文学习网 - HTML5先行者学习网

get(object, name)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个获得对象属性的 promise。XGSHTML5中文学习网 - HTML5先行者学习网

post(object, name, args)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个调用对象方法的 promise。XGSHTML5中文学习网 - HTML5先行者学习网

put(object, name, value)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个修改对象属性的 promise。XGSHTML5中文学习网 - HTML5先行者学习网

del(object, name)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个删除对象属性的 promise。XGSHTML5中文学习网 - HTML5先行者学习网

makePromise(descriptor Object, fallback Function)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个 promise 对象,该对象必须是一个可调用的函数,也可能是可被实例化的构造函数。XGSHTML5中文学习网 - HTML5先行者学习网

  • 第一个参数接受一个描述对象,该对象结构如下,XGSHTML5中文学习网 - HTML5先行者学习网
{ "when": function(errback){...}, "get": function(name){...}, "put": function(name, value){...}, "post": function(name, args){...}, "del": function(name){...}, } 

上面每一个注册的 handle 都返回一个 resolved value或者 promise。XGSHTML5中文学习网 - HTML5先行者学习网

  • 第二个参数接受一个 fallback(message,...args) 函数,当没有 promise 对象没有找到对应的 handle 时该函数会被触发,返回一个 resolved value 或者 promise。

defer()XGSHTML5中文学习网 - HTML5先行者学习网
返回一个对象,该对象包含一个 resolve(value) 方法和一个 promise 属性。XGSHTML5中文学习网 - HTML5先行者学习网
当 resolve(value) 方法被第一次调用时,promise 属性的状态变成 完成,所有之前或之后观察该 promise 的 promise 的状态都被转变成 完成。value 参数如果不是一个 promise ,会被包装成一个 promise 的 ref。resolve 方法会忽略之后的所有调用。XGSHTML5中文学习网 - HTML5先行者学习网

reject(reason String)XGSHTML5中文学习网 - HTML5先行者学习网
返回一个被标记为 失败 的 promise。XGSHTML5中文学习网 - HTML5先行者学习网
一个失败的 promise 上被调用 when(message) 方法时,会采用如下两种方法之一XGSHTML5中文学习网 - HTML5先行者学习网
1. 如果存在 errback,errback 会以 reason 作为参数被调用。when方法会将 errback 的返回值返回。XGSHTML5中文学习网 - HTML5先行者学习网
2. 如果不存在 errback,when 方法返回一个新的 reject 状态的promise 对象,以同一 reason 作为参数。XGSHTML5中文学习网 - HTML5先行者学习网

ref(value)XGSHTML5中文学习网 - HTML5先行者学习网
如果 value 是 promise 对象,返回 value 本身。否则,返回一个resolved 的 promise,携带如下 handle。XGSHTML5中文学习网 - HTML5先行者学习网
1. when(errback),忽略 errback,返回 resolved 值XGSHTML5中文学习网 - HTML5先行者学习网
2. get(name),返回 resolved 值的对应属性。XGSHTML5中文学习网 - HTML5先行者学习网
3. put(name, value) ,设置 resolved 值的对应属性。XGSHTML5中文学习网 - HTML5先行者学习网
4. del(name),删除 resolved 值的对应属性。XGSHTML5中文学习网 - HTML5先行者学习网
5. post(name, args), 调用 resolved 值的对应方法。XGSHTML5中文学习网 - HTML5先行者学习网
6. 其他所有的调用都返回一个 reject,并携带 "Promise does not handle NAME" 的理由。XGSHTML5中文学习网 - HTML5先行者学习网

isPromise(value) BooleanXGSHTML5中文学习网 - HTML5先行者学习网
判断一个对象是否是 promiseXGSHTML5中文学习网 - HTML5先行者学习网

method(name String)XGSHTML5中文学习网 - HTML5先行者学习网
获得一个返回 name 对应方法的 promise。返回值是 "get", "put", "del" 和 "post" 对应的方法,但是会在下一事件循环返回。XGSHTML5中文学习网 - HTML5先行者学习网

Promises/D 规范XGSHTML5中文学习网 - HTML5先行者学习网
为了增加不同 promise 实现之间的可互操作性,Promises/D 规范对promise 对象和 Promises/B 规范做了进一步的约定。以达到鸭子类型的效果(Duck-type Promise)。XGSHTML5中文学习网 - HTML5先行者学习网

简单来说Promises/D 规范,做了两件事情,XGSHTML5中文学习网 - HTML5先行者学习网

1、如何判断一个对象是 Promise 类型。XGSHTML5中文学习网 - HTML5先行者学习网
2、对 Promises/B 规范进行细节补充。XGSHTML5中文学习网 - HTML5先行者学习网
甄别一个 Promise 对象XGSHTML5中文学习网 - HTML5先行者学习网
Promise 对象必须是实现 promiseSend 方法。XGSHTML5中文学习网 - HTML5先行者学习网
1. 在 promise 库上下文中,如果对象包含 promiseSend 方法就可以甄别为promise 对象XGSHTML5中文学习网 - HTML5先行者学习网
2. promiseSend 方法必须接受一个操作名称,作为第一个参数XGSHTML5中文学习网 - HTML5先行者学习网
3. 操作名称是一个可扩展的集合,下面是一些保留名称XGSHTML5中文学习网 - HTML5先行者学习网
1. when,此时第三个参数必须是 rejection 回调。XGSHTML5中文学习网 - HTML5先行者学习网
1. rejection回调必须接受一个 rejection 原因(可以是任何值)作为第一个参数XGSHTML5中文学习网 - HTML5先行者学习网
2. get,此时第三个参数为属性名(字符串类型)XGSHTML5中文学习网 - HTML5先行者学习网
3. put,此时第三个参数为属性名(字符串类型),第四个参数为新属性值。XGSHTML5中文学习网 - HTML5先行者学习网
4. del,此时第三个参数为属性名XGSHTML5中文学习网 - HTML5先行者学习网
5. post,此时第三个参数为方法的属性名,接下来的变参为方法的调用参数XGSHTML5中文学习网 - HTML5先行者学习网
6. isDefXGSHTML5中文学习网 - HTML5先行者学习网
4. promiseSend方法的第二个参数为 resolver 方法XGSHTML5中文学习网 - HTML5先行者学习网
5. promiseSend方法可能接受变参XGSHTML5中文学习网 - HTML5先行者学习网
6. promiseSend方法必须返回undefinedXGSHTML5中文学习网 - HTML5先行者学习网

对 Promises/B 规范的补充XGSHTML5中文学习网 - HTML5先行者学习网
Promises/D 规范中对 Promises/B 规范中定义的ref、reject、def、defer方法做了进一步细致的约束,此处略去这些细节。XGSHTML5中文学习网 - HTML5先行者学习网

Promises/A+ 规范XGSHTML5中文学习网 - HTML5先行者学习网
前面提到的 Promises/A/B/D 规范都是有CommonJS组织提出的,Promises/A+是有一个自称为Promises/A+ 组织发布的,该规范是以Promises/A作为基础进行补充和修订,旨在提高promise实现之间的可互操作性。XGSHTML5中文学习网 - HTML5先行者学习网

Promises/A+ 对.then方法进行细致的补充,定义了细致的Promise Resolution Procedure流程,并且将.then方法作为promise的对象甄别方法。XGSHTML5中文学习网 - HTML5先行者学习网

此外,Promises/A+ 还提供了兼容性测试工具,以确定各个实现的兼容性。XGSHTML5中文学习网 - HTML5先行者学习网

实现一个迷你版本的PromiseXGSHTML5中文学习网 - HTML5先行者学习网
上面扯了这么多规范,现在我们看看如何实现一个简单而短小的Promise。XGSHTML5中文学习网 - HTML5先行者学习网

1、状态机XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

var PENDING = 0;var FULFILLED = 1;var REJECTED = 2;function Promise() { // store state which can be PENDING, FULFILLED or REJECTED var state = PENDING; // store value or error once FULFILLED or REJECTED var value = null; // store sucess & failure handlers attached by calling .then or .done var handlers = [];}

2、状态变迁XGSHTML5中文学习网 - HTML5先行者学习网
仅支持两种状态变迁,fulfill和rejectXGSHTML5中文学习网 - HTML5先行者学习网

XGSHTML5中文学习网 - HTML5先行者学习网

// ...function Promise() {  // ... function fulfill(result) {  state = FULFILLED;  value = result; } function reject(error) {  state = REJECTED;  value = error; }}

fulfill和reject方法较为底层,通常更高级的resolve方法开放给外部。XGSHTML5中文学习网 - HTML5先行者学习网

XGSHTML5中文学习网 - HTML5先行者学习网

// ...function Promise() { // ... function resolve(result) {  try {   var then = getThen(result);   if (then) {    doResolve(then.bind(result), resolve, reject)    return   }   fulfill(result);  } catch (e) {   reject(e);  } }}

resolve方法可以接受一个普通值或者另一个promise作为参数,如果接受一个promise作为参数,等待其完成。promise不允许被另一个promise fulfill,所以需要开放resolve方法。resolve方法依赖一些帮助方法定义如下:XGSHTML5中文学习网 - HTML5先行者学习网

XGSHTML5中文学习网 - HTML5先行者学习网

/** * Check if a value is a Promise and, if it is, * return the `then` method of that promise. * * @param {Promise|Any} value * @return {Function|Null} */function getThen(value) { var t = typeof value; if (value && (t === 'object' || t === 'function')) {  var then = value.then;  if (typeof then === 'function') {   return then;  } } return null;}/** * Take a potentially misbehaving resolver function and make sure * onFulfilled and onRejected are only called once. * * Makes no guarantees about asynchrony. * * @param {Function} fn A resolver function that may not be trusted * @param {Function} onFulfilled * @param {Function} onRejected */function doResolve(fn, onFulfilled, onRejected) { var done = false; try {  fn(function (value) {   if (done) return   done = true   onFulfilled(value)  }, function (reason) {   if (done) return   done = true   onRejected(reason)  }) } catch (ex) {  if (done) return  done = true  onRejected(ex) }}

这里resolve和doResolve之间的递归很巧妙,用来处理promise的层层嵌套(promise的value是一个promise)。XGSHTML5中文学习网 - HTML5先行者学习网

构造器XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

// ...function Promise(fn) {  // ...  doResolve(fn, resolve, reject);}

.done方法XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

// ...function Promise(fn) { // ... function handle(handler) {  if (state === PENDING) {   handlers.push(handler);  } else {   if (state === FULFILLED &&    typeof handler.onFulfilled === 'function') {    handler.onFulfilled(value);   }   if (state === REJECTED &&    typeof handler.onRejected === 'function') {    handler.onRejected(value);   }  } } this.done = function (onFulfilled, onRejected) {  // ensure we are always asynchronous  setTimeout(function () {   handle({    onFulfilled: onFulfilled,    onRejected: onRejected   });  }, 0); } // ...}

.then方法XGSHTML5中文学习网 - HTML5先行者学习网
XGSHTML5中文学习网 - HTML5先行者学习网

// ...function Promise(fn) {  // ...  this.then = function (onFulfilled, onRejected) {   var self = this;   return new Promise(function (resolve, reject) {    return self.done(function (result) {     if (typeof onFulfilled === 'function') {      try {       return resolve(onFulfilled(result));      } catch (ex) {       return reject(ex);      }     } else {      return resolve(result);     }    }, function (error) {     if (typeof onRejected === 'function') {      try {       return resolve(onRejected(error));      } catch (ex) {       return reject(ex);      }     } else {      return reject(error);     }    });   });  }  // ...}

$.promiseXGSHTML5中文学习网 - HTML5先行者学习网
jQuery 1.8 之前的版本,jQuery的 then 方法只是一种可以同时调用 done 、fail 和 progress 这三种回调的速写方法,而 Promises/A 规范的 then 在行为上更像是 jQuery 的 pipe。 jQuery 1.8 修正了这个问题,使 then 成为 pipe 的同义词。不过,由于向后兼容的问题,jQuery 的 Promise 再如何对 Promises/A 示好也不太会招人待见。XGSHTML5中文学习网 - HTML5先行者学习网

此外,在 Promises/A 规范中,由 then 方法生成的 Promise 对象是已执行还是已拒绝,取决于由 then 方法调用的那个回调是返回值还是抛出错误。在 JQuery 的 Promise 对象的回调中抛出错误是个糟糕的主意,因为错误不会被捕获。XGSHTML5中文学习网 - HTML5先行者学习网

小结XGSHTML5中文学习网 - HTML5先行者学习网
最后一个例子揭示了,实现 Promise 的关键是实现好 doResolve 方法,在完事以后触发回调。而为了保证异步 setTimeout(fun, 0); 是关键一步。XGSHTML5中文学习网 - HTML5先行者学习网

Promise 一直用得蛮顺手的,其很好的优化了 NodeJS 异步处理时的代码结构。但是对于其工作原理却有些懵懂和好奇,于是花了些精力查阅并翻译了Promise 的规范,以充分的理解 Promise 的细节。XGSHTML5中文学习网 - HTML5先行者学习网

以上就是关于JavaScript中Promise的使用方法介绍,希望对大家的学习有所帮助。XGSHTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助