[翻译]简单的实现一个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 ...
随机推荐
- NDK开发,如何配置 debug环境
刚开始做NDK 开发的时候,Android Studio 还没提供了 native C/C++ 设置断点 调试,我们都是通过输出 日志来调试,这样费时耗力.Android Studio 应该是在 2. ...
- Halcon一日一练:图像拼接技术2:步骤与例程
上一篇主要介绍了图像拼接的一些原理和方法,这一篇将主要介绍步骤和例程: 接上一篇: 基于特征的接拼方法,分为四个步骤 1.特征检测:从图像中检测出显著且独特的图像特征,诸如:闭合区域,直线段,边缘,轮 ...
- IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理
1.前言 一个安全的信息系统,合法身份检查是必须环节.尤其IM这种以“人”为中心的社交体系,身份认证更是必不可少. 一些PC时代小型IM系统中,身份认证可能直接做到长连接中(也就是整个IM系统都是以长 ...
- spring 运行时属性值注入
继续spring学习,今天介绍两种外部属性值注入的方式.当你需要读取配置信息时,可以快速读取. 开始之前先创建属性文件site.properties,放在classpath下面 #数据库配置 ### ...
- Yii2 灵活加载js、css
Yii2.0对于CSS/js 管理,使用AssetBundle资源包类. 视图如何按需加载CSS/JS ? 资源包定义: backend/assets/AppAsset.PHP <?php na ...
- Egret学习笔记 (Egret打飞机-1.大致思路)
大致看了一遍Egret的官方文档,就开始打算使用Egret来开发一个打飞机游戏. 首先来捋一捋思路,先来看一看一个打飞机游戏的图片 基本上一个打飞机游戏分为 开始游戏 ----------进入游戏 ...
- nyoj720 项目安排 二分+dp
思路:dp(i)表示前i个项目的最大收益,转移方程很好写dp(i) = max{ dp(k) + val(i) },val(i)表示第i个项目的价值,dp(k)表示前k个的最佳收益,k满足ed(k) ...
- Docker系列二:Docker的基本结构
Docker的基本结构 Docker 的三大基础组件 Docker有三个重要的概念:仓库 , 镜像 和 容器 ,它们是Docker的三大基出组件 Docker的组织结构 Docker处于操作系统和虚拟 ...
- 微信企业号JS-SDK选择图片、上传图片
因公司项目需要,要修改一个手机端上传图片的一个功能,原本的项目用的是input 的file控件上传的,虽然标注了可以多选,但是在实际运用当中只有iOS手机可以实现多选,Android手机并不支持多选, ...
- 最短路径问题(Floyd-Warshall模板)
#include<bits/stdc++.h> using namespace std; int n; int x,y; ][]; ][]; int m,s,t; int main() { ...