英文原文为: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. js中的isNaN()函数

    <html> <head> <script type="text/javascript" src="function.js"> ...

  2. es2015及es2017对我们的编程方式造成了什么影响?

    记一些写代码中用得到的es6+语法,至于什么正则的拓展,数组的什么fill方法,对我们来说用处不大,就不提及了. 还有es6的import模块和class模块,这些在各种框架中都有体现,而且语法简单, ...

  3. CentOS下安装配置cmake

    安装环境:CentOS-6.4   安装方式:源码编译安装  软件:cmake-2.8.5.tar.gz 下载地址暂时不提供,去百度搜一下准有 安装前提 系统中已经安装了gcc. ncurses-de ...

  4. Ubuntu下Maven配置与Maven项目创建教程

    一. Ubuntu下Maven配置 windows下Maven配置参考http://www.cnblogs.com/LexMoon/p/JavaMaven.html ubuntu下Maven地址htt ...

  5. UVALive - 3644 X-Plosives (并查集)

    思路:每一个product都可以作一条边,每次添加一条边,如果这边的加入使得某个集合构成环,就应该refuse,那么就用并查集来判断. AC代码: //#define LOCAL #include & ...

  6. UVA1601 状态搜索

    很有意思的一道题,就是迷宫问题的增强版.但是细节很多,有一个技巧就是把每个可以走的位置编号方便状态判重. AC代码: #include<cstdio> #include<cstrin ...

  7. HDU - 1495 bfs [kuangbin带你飞]专题一

    模拟倒水的过程,每次可以把第i个杯子的水向第j个杯子里面倒,这可能出现新的状态,不停的更新状态,指导某两个杯子的水等于S/2说明找到答案,如果所有状态搜索完毕仍然不能均分,则退出. 注意:如果S是奇数 ...

  8. 【BZOJ3529】【SDOI2014】 数表

    Time Limit: 10 Sec Memory Limit: 512 MB Description ​ 有一张\(n×m\)的数表,其第i行第j列(\(,1 \le i \leq n,1 \le ...

  9. 内置函数--global() 和 local()

    一 . globals :返回当前作用域内全局变量的字典.   >>> globals() {'__spec__': None, '__package__': None, '__bu ...

  10. JDBC底层原理

    Class.forName(“com.mysql.jdbc.Driver”)是 强制JVM将com.mysql.jdbc.Driver这个类加载入内存,并将其注册到DriverManager类,然后根 ...