[翻译]简单的实现一个Promise
英文原文为: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的更多相关文章
- 【原】手写一个promise
上一篇文章中,我们介绍了Promise的基本使用,在这篇文章中,我们试着自己来写一个Promise,主要是学习Promise的内部机制,学习它的编程思想. !!!备注:本文写的不好,仅供自己学习之用, ...
- 简单实现异步编程promise模式
本篇文章主要介绍了异步编程promise模式的简单实现,并对每一步进行了分析,需要的朋友可以参考下 异步编程 javascript异步编程, web2.0时代比较热门的编程方式,我们平时码的时候也或多 ...
- 教你一步一步实现一个Promise
Promise我想现在大家都非常熟悉了,主要作用就是解决异步回调问题,这里简单介绍下. Promise规范是CommonJS规范之一,而Promise规范又分了好多种,比如 Promises/A.Pr ...
- 简单谈谈js中Promise的用法
首先先推荐一篇博文:http://blog.csdn.net/jasonzds/article/details/53717501 这篇博文很清晰的说明了Promise的用法,这里来简单总结一下: Pr ...
- Promise原理—一步一步实现一个Promise
promise特点 一个promise的当前状态只能是pending.fulfilled和rejected三种之一.状态改变只能是pending到fulfilled或者pending到rejected ...
- Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)
1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...
- 我在阿里这仨月 前端开发流程 前端进阶的思考 延伸学习的方式很简单:google 一个关键词你能看到十几篇优秀的博文,再这些博文中寻找新的关键字,直到整个大知识点得到突破
我在阿里这仨月 Alibaba 试用期是三个月,转眼三个月过去了,也到了转正述职的时间.回想这三个月做过的事情,很多很杂,但还是有重点. 本文谈一谈工作中遇到的各种场景,需要用到的一些前端知识,以及我 ...
- 掘金转载-手写一个Promise
目录 一 什么是Promise ? 二 Promises/A+ 规范 2.1 术语 2.2 基本要求 2.2.1. Promise的状态 2.2.2. Then 方法 2.3 简易版实践 2.4 进一 ...
- 实现一个Promise
实现一个Promise promise特点 一个promise的当前状态只能是pending.fulfilled和rejected三种之一.状态改变只能是pending到fulfilled或者pend ...
随机推荐
- 【Unity3D技术文档翻译】第1.8篇 AssetBundles 问题及解决方法
上一章:[Unity3D技术文档翻译]第1.7篇 AssetBundles 补丁更新 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Deve ...
- mac中的myeclipse的控制台中文乱码问题解决办法
之前写java用到控制台的主要是字符和数字,中文输入貌似真的还没用过,所以就遇到了一个悲剧的老问题,估计每个程序员都会遇到——中文乱码. 用的是MyEclipse开发环境,Window->Gen ...
- Nginx和Apache有什么区别?
Nginx抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能. Apache rewrite ,比nginx 的rewrite ...
- HDU - 2612 bfs [kuangbin带你飞]专题一
分别以两个人的家作为起点,bfs求得到每个KFC最短距离.然后枚举每个KFC,求得时间之和的最小值即可. 此题不符合实际情况之处: 通过了一个KFC再去另一个KFC可以吗? 出题人都没好好想过吗? ...
- JavaScript基础教程2-20160612
1.JavaScript之操作html元素,Dom Dom是抽象出来的网页对象,需要了解面向对象的思想:调用对象下的方法实现相应的功能 使用JS调用dom来创建标签. //document是网页对象 ...
- HDP2.0测试
1.测试Hbase (1)hive导入hbase
- python︱字符操作杂记(split、zip...)
字符串特别是中文在python里面还是有很多需要注意的地方. . . . 一.字符串 . . 1.字符串连接 方式一:单个字符相连用 + 就可以: 方式二:list组内相连,可以用join: 方式三: ...
- 1.3 PCI总线的存储器读写总线事务
总线的基本任务是实现数据传送,将一组数据从一个设备传送到另一个设备,当然总线也可以将一个设备的数据广播到多个设备.在处理器系统中,这些数据传送都要依赖一定的规则,PCI总线并不例外. PCI总线使用单 ...
- OkHttp使用教程——网络操作之OkHttp, Volley以及Gson
写这篇文章的动机 在安卓项目中有一个问题可能无法避免:网络.不管你是加载图片,请求API数据还是从因特网上获得一个字节,你都是在使用网络. 鉴于网络在安卓中的重要性与基础性,当今安卓开发者面临的问题之 ...
- configure: error: xml2-config not found. Please check your libxml2 installation
安装php时的报错 checking libxml2 install dir... nochecking for xml2-config path... configure: error: xml2- ...