[翻译]简单的实现一个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 ...
随机推荐
- 谈谈语音通信中的各种tone
今天谈的这个主题(tone)存在于我们的日常打电话过程中.先举两个场景:1,你拿起固话话筒准备打电话,按电话号码前先从话筒里听到"嗡"的连续音,这叫dial tone(拨号音,表示 ...
- SpringMvc自动装配@Controller无效
1.问题原因:SpringMvc驱动器没有扫描该Controller层 虽然配置了 <!-- 启用spring mvc 注解 --> <context:annotation-conf ...
- web项目中js加载慢问题解决思路
最近使用Echarts地图(版本为echarts2,echarts3目前无法下载地图版). 问题描述:之前使用require形式加载,地图首次加载显示要6-7秒,难以接受. js配置代码如下: < ...
- 3道acm简单题(2011):1.判断是否能组成三角形;2.判断打鱼还是晒网;3.判断丑数。
//1.输入三个正整数A.B.C,判断这三个数能不能构成一个三角形.//思路:最小的两边之和是否是大于第三边#include<iostream>#include<algorithm& ...
- PAT All Roads Lead to Rome 单源最短路
思路:单源最短路末班就好了,字符串映射成数字处理. AC代码 //#define LOCAL #include <stdio.h> #include <string.h> #i ...
- SpringCloud入门1-服务注册与发现(Eureka)
前言 Oracle转让Java,各种动态语言的曝光率上升,Java工程师的未来在哪里?我觉得Spring Cloud让未来有无限可能.拖了半年之久的Spring Cloud学习就从今天开始了.中文教材 ...
- Redis 设置开机启动
1. 将下列代码保存为文件redis, 置于 /etc/init.d 下面 ########################### # chkconfig: 2345 90 10 redis服务必须在 ...
- Docker系统五:Docker仓库
创建Docker Hub账户 登录和上传镜像到Hub.docker.com docker login //登陆hub.docker.com docker tag ubutun1404-baseimag ...
- arm-linux-gcc: Command not found 问题解析 .
问题: sudo tar jxvf cross-2.95.3.tar.bz2 export PATH=$PATH:/usr/local/arm/2.95.3/bin 使用arm-linux-gcc – ...
- Hi3515支持NFS-ROOT启动
目前在做Hi3515平台监控项目,前期开发一直使用SDK里推荐的mount nfs方式来调试代码,虽然也算方便,但是我一直觉得用法NFS-ROOT才是最省事的方法,而且最接近最终用户使用环境,因为如果 ...