手写一个符合Promise/A+规范的Promise
2019-10-14 本文已影响0人
成熟稳重的李先生
Promise的基本概念:
Promise使异步脱离了回调地狱,可以更优雅的操作异步函数的执行结果。究其根本,不过是使用了发布/订阅来达到这一效果。
- 1.promise有三种状态, “pending”,“resolved”, “rejected”。只能由“pending”转化为“resolved”或者由“pending”转化为“rejected”。状态改变后,不能再次改变!
- 2.回顾下发布/订阅模式,再对照promise。即then时,将成功和失败函数分别保存到订阅列表。执行原函数(一般是异步),当成功/失败后,分别调用成功/失败保存的函数
function Promise(executor){ // executor是用户要执行的异步方法(立即执行)
this.status = "pending"; // 初始状态
this.value = undefined; //成功的值
this.reason = undefined; // 失败的值(原因)
this.onResolvedCallbacks = []; // “成功”的订阅者
this.onRejectedCallbacks = []; // “失败”的订阅者
let self = this;
function resolve(value){ // resolve/reject这两个方法,都是用户主动调用的
self.status = "resolved"; // 改变promise状态
self.value = value; //成功的值
self.onResolvedCallbacks.forEach(fn => fn()); // 发布这个“成功”的消息
}
function reject(reason){
self.status = "rejected";
self.reason = reason; // 失败的原因
self.onRejectedCallbacks.forEach(fn => fn()); // 发布这个“失败”的消息
}
try {
executor(resolve, reject); // 立即执行用户的异步方法,并且将这两个出发函数传递给用户
}catch(e){
reject(e); // 异常也视为失败
}
}
Promise.prototype.then = function(onFulfilled, onRejected){
onFulfilled = (typeof onFulfilled === "function") ? onFulfilled : val => val; // promise有向下传递的特性,如果不处理,直接将值传递给下一层
onRejected = (typeof onRejected === "function") ? onRejected : reason => {
throw reason;
};
let self = this;
let promise2 = new Promise((resolve, reject) => { // 这就是为什么可以一直then(因为then返回的还是一个promise)
if(self.status === "resolved"){ // 如果这个异步已经成功,那么直接调用
setTimeout(() => { //这里使用setTimeout是,因为在下边代码中要使用promise2,如果是同步的话,就拿不到promise2,因此需要将其放入下一个队列中
try {
let x = onFulfilled(self.value); // 执行成功的函数(有可能它还返回promise,因此如下有函数“resolvePromise”)
resolvePromise(promise2, x, resolve, reject); //处理这个结果
}catch(e){
reject(e); // 如果函数执行失败,那么会走向下一个then的失败状态
}
}, 0)
}else if(self.status === "rejected"){
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0)
}else{
self.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e)
}
}, 0)
});
self.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}, 0)
})
}
})
return promise2;
}
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x){
return reject(new TypeError("循环引用了"));
}
let called = false;
if(x !== null && (typeof x === "object" || typeof x === "function")){ // 判断x是否为简单类型值,是则直接resolve,否则继续
try {
let then = x.then;
if(typeof then === "function"){ // 判断其是否有then
then.call(x, y => {
if(called) return;
called = true;
resolvePromise(promise2, y, resolve, reject); // 继续判断这个结果,直到其返回一个简单(非promise)型的值
}, r => {
if(called) return;
called = true;
reject(r);
})
}else{
//当前then是一个普通对象,直接resolve
if(called) return;
called = true;
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e)
}
}else{
if(called) return;
called = true;
resolve(x);
}
}
Promise.defer = Promise.deferred = function(){ //
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
module.exports = Promise;
如何知道是否符合规范呢?
请查看文档 Promise/A+。
同时,还可以使用包“promises-aplus-tests”来测试你的promise是否符合规范。
使用方式:
yarn add promises-aplus-tests -g
//在你的工作目录下
promises-aplus-tests xxx.js //(共872条测试用例)