英文原文为:https://www.promisejs.org/implementing/

1. 状态机

因为 promise 对象是一个状态机,所以我们首先应该定义将要用到的状态。

var PENDING = 0;
var FULFILLED = 1;
VAR REJECTED = 2; function Promise () {
// 可以存储这些状态,PENDING、FULFILLED 或 REJECTED
var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息
var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数
var handlers = [];
}

2. 转换

接着,让我们来考虑一下两个可能发生的重要转换,fulfilling 和 rejecting:

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2; function Promise () {
// 可以存储这些状态,PENDING、FULFILLED 或 REJECTED
var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息
var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数
var handlers = []; function fulfill (result) {
state = FULFILLED;
value = result;
} function reject (error) {
state = REJECTED;
value = error;
}
}

这给了我们基础的低层转换,我们现在来考虑更高层的转换 resolve。

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2; function Promise () {
// 可以存储这些状态,PENDING、FULFILLED 或 REJECTED
var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息
var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数
var handlers = []; function fulfill (result) {
state = FULFILLED;
value = result;
} function reject (error) {
state = REJECTED;
value = error;
} 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 对象还是一个基本值(plain value),如果是一个 promise 对象,如何等待他完成。

/**
* 检查值是否是一个 Promise 对象, 如果他是,
* 返回这个 Promise 对象的‘then’方法。
*
* @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;
} /**
* 潜在的解析函数,以确保 onFulfilled 和 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);
}
}

3. 构造

我们现在有了完整的内部状态机,但我们还没有暴露出解决承诺(resolving promise)或观察它的方法。让我们从增加一个解决 promise 的方法开始。

var PENDING = 0;
var FULFILLED = 1;
VAR REJECTED = 2; function Promise () {
// 可以存储这些状态,PENDING、FULFILLED 或 REJECTED
var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息
var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数
var handlers = []; function fulfill (result) {
state = FULFILLED;
value = result;
} function reject (error) {
state = REJECTED;
value = error;
} function resolve (result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject);
return;
}
fulfill(result);
} catch (e) {
reject(e);
}
} doResolve(fn, resolve, reject);
}

你可以看到,我们复用了 doResolve,因为我们有另一个不可信的解析。fn 允许多次调用 resolve 和 reject,甚至抛出异常。我们要确保 promise 只 resolve 一次或 reject 一次,然后再也不会过渡到另一个状态。

4. 观察(使用 .done)

我们现在拥有一个已完成的状态机,但是我们仍没有办法去观察它的变化。我们的最终目的是实现 .then,但是 .done 的语义要简单的多,所以我们首先实现它。

我们这里的目标是实现 promise.done(onFulfilled, onRejected):

  • 只调用 onFulfilled 或 onRejected 中的一个
  • 它是调用一次
  • 它在下一时刻被调用(例如,在 .done 方法已经返回后)
  • 不管我们在调用之前或之后是否解决了这个问题,它都被调用了。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2; function Promise (fn) {
// 可以存储这些状态,PENDING、FULFILLED 或 REJECTED
var state = PENDING; // 当为 FULFILLED 或 REJECTED 状态时,存储值或错误信息
var value = null; // 存储被 .then 或 .done 方法调用的成功和失败的处理函数
var handlers = []; function fulfill(result) {
state = FULFILLED;
value = result;
handlers.forEach(handle);
handlers = null;
} function reject (result) {
state = REJECTED
value = result
handlers.forEach(handle)
handlers = null
} function resolve (result) {
try {
var then = getThen(result)
if (then) {
doResolve(then, resolve, reject)
return
}
fulfill(result)
} catch (ex) {
reject(ex)
}
} function handle (handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED && typeof handlers.onFulfilled === 'function') {
handler.onFulfilled(value);
}
if (state === REJECTED && typeof handlers.onRejected === 'function') {
handler.onRejected(value);
}
}
} this.done = function (onFulfilled, onRejected) {
// 确保我们总是异步执行的
setTimeout(function () {
handler({
onFulfilled: onFulfilled,
onRejected: onRejected
})
}, 0)
} doResolve(fn, resolve, reject);
}

当 Promise 被解决或拒绝时,我们要确保去通知 handlers。

5. 观察(使用 .then)

现在我们已经实现了 .done,我们可以简单的实现 .then 来实现相同的事情,但是在程序中构造一个新的 Promise 对象。

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

[翻译]简单的实现一个Promise的更多相关文章

  1. 【原】手写一个promise

    上一篇文章中,我们介绍了Promise的基本使用,在这篇文章中,我们试着自己来写一个Promise,主要是学习Promise的内部机制,学习它的编程思想. !!!备注:本文写的不好,仅供自己学习之用, ...

  2. 简单实现异步编程promise模式

    本篇文章主要介绍了异步编程promise模式的简单实现,并对每一步进行了分析,需要的朋友可以参考下 异步编程 javascript异步编程, web2.0时代比较热门的编程方式,我们平时码的时候也或多 ...

  3. 教你一步一步实现一个Promise

    Promise我想现在大家都非常熟悉了,主要作用就是解决异步回调问题,这里简单介绍下. Promise规范是CommonJS规范之一,而Promise规范又分了好多种,比如 Promises/A.Pr ...

  4. 简单谈谈js中Promise的用法

    首先先推荐一篇博文:http://blog.csdn.net/jasonzds/article/details/53717501 这篇博文很清晰的说明了Promise的用法,这里来简单总结一下: Pr ...

  5. Promise原理—一步一步实现一个Promise

    promise特点 一个promise的当前状态只能是pending.fulfilled和rejected三种之一.状态改变只能是pending到fulfilled或者pending到rejected ...

  6. Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)

    1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...

  7. 我在阿里这仨月 前端开发流程 前端进阶的思考 延伸学习的方式很简单:google 一个关键词你能看到十几篇优秀的博文,再这些博文中寻找新的关键字,直到整个大知识点得到突破

    我在阿里这仨月 Alibaba 试用期是三个月,转眼三个月过去了,也到了转正述职的时间.回想这三个月做过的事情,很多很杂,但还是有重点. 本文谈一谈工作中遇到的各种场景,需要用到的一些前端知识,以及我 ...

  8. 掘金转载-手写一个Promise

    目录 一 什么是Promise ? 二 Promises/A+ 规范 2.1 术语 2.2 基本要求 2.2.1. Promise的状态 2.2.2. Then 方法 2.3 简易版实践 2.4 进一 ...

  9. 实现一个Promise

    实现一个Promise promise特点 一个promise的当前状态只能是pending.fulfilled和rejected三种之一.状态改变只能是pending到fulfilled或者pend ...

随机推荐

  1. cocos2d-x中处理touch事件

    在cocos2d-x中, touch事件分为两种:一种是单点事件, 另一种是多点事件. 单点事件对应的代理方法是: virtual bool ccTouchBegan(CCTouch *pTouch, ...

  2. statement preparestatement CallableStatement

    大家都知道Statement.PrepareStatement 和CallableStatement 对象,其实它们是interface,为什么JDBC2.0中要提供这三个对象呢?对于Statemen ...

  3. yii2高级模板使用一个域名管理前后台

    yii2的高级模板分为backend和frontend,最开始用yii的时候并没怎么在意,就使用了两个域名分别解析前后台.今天无意间看见 可以使用一个域名指向前后台. 1.修改 advanced/ba ...

  4. Batch Normalization&Dropout浅析

    一. Batch Normalization 对于深度神经网络,训练起来有时很难拟合,可以使用更先进的优化算法,例如:SGD+momentum.RMSProp.Adam等算法.另一种策略则是高改变网络 ...

  5. POJ - 1062 昂贵的聘礼 Dijkstra

    思路:构造最短路模型,抽象出来一个源点,这个源点到第i个点的费用就是price[i],然后就能抽象出图来,终点是1. 任意两个人之间都有等级限制,就枚举所有最低等级限制,然后将不再区间[min_lev ...

  6. python如何使用pymysql模块

    Python 3.x 操作MySQL的pymysql模块详解 前言pymysql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而M ...

  7. bonding实现网卡负载均衡与高可用

    bondingLinux bonding 驱动提供了一个把多个网络接口设备捆绑为单个的网络接口设置来使用,用于网络负载均衡及网络冗余.他是解决同一个IP下突破网卡的流量限制的工具,网卡网线对吞吐量是有 ...

  8. 程序bug致损失400亿,判程序员坐牢? 搞笑我们是认真的

    号外!号外!走过,路过,不要错过!日本 IT 业的狗血八卦继续独家放送啦!! 2015 年 9 月 3 日,随着东京最高法院驳回瑞穗证券的上诉,维持二审的原判结果,一个长达 10 年的诉讼终于画下了句 ...

  9. MongoDB集群之分片

    原文:点击打开链接 MongoDB分片 分片(sharding)是将数据拆分,将其分散在不同的机器上的过程.MongoDB支持自动分片 片键(shard key)设置分片时,需要从集合里面选一个键,用 ...

  10. Caused by: java.lang.ClassNotFoundException: com.mchange.v2.ser.Indirector

    1.错误描述 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -help ...