Promise的实现原理
主要难点的实现是链式调用
栗子
let = requestData = ()=>{
return new Promise((resolve,reject)=>{
resolve("1");
});
};
requestData.then((data)=>{
console.log(data);
},(error)=>{
console.log(error);
});Promise状态机
我们现在按照这个栗子来简单的实现下:
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
class Promise01 {
constructor(excutor) {
if (typeof excutor !== "function") {
throw new Error("promise need a function");
}
// 默认状态是等待态
this.status = PENDING;
//存放成功的值
this.resolvedValue = null;
//存放失败的值
this.rejectedValue = null;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks = [];
let self = this;
let resolve = function(data) {
if (self.status === PENDING) {
self.resolvedValue = data;
self.status = RESOLVED;
self.onResolvedCallbacks.forEach(fn => fn(self.resolvedValue));
}
};
let reject = function(error) {
if (self.status === PENDING) {
self.rejectedValue = error;
self.status = REJECTED;
self.onRejectedCallbacks.forEach(fn => fn(self.rejectedValue));
}
};
try {// 执行时可能会发生异常
excutor(resolve, reject);
} catch (error) {// promise失败了
reject(error);
}
}
then(resolvedHandler, rejectedHandler) {
if (this.status === PENDING) { // 当前既没有完成 也没有失败
this.onResolvedCallbacks.push(resolvedHandler);
this.onRejectedCallbacks.push(rejectedHandler);
} else if (this.status === RESOLVED) {// 当前成功状态
resolvedHandler(this.resolvedValue);
} else if (this.status === REJECTED) {// 当前失败状态
resolvedHandler(this.rejectedValue);
}
//return this;
}
}这里虽然实现了.then方法,但是如果需要promise.then().then()的话就会有问题。
Promise的链式调用
this链式调用弊端
我们知道Jquery的链式调用就是返回this,就可以实现链式调用。那Promise里面的链式调用怎么实现的。
我们只需要把上面then方法中的最后一行return this的注释去掉就好了.这里就不重复粘贴代码了。
return this;let requestData = () => {
return new Promise01((resolve, reject) => {
setTimeout(() => {
resolve("1");
}, 1000);
});
};
requestData().then((data) => {
console.log(data);
return "2";}).then((data) => {
console.log(data);
});我们run一下这个栗子就知道,返回值是两个“1”。很明显,我的期望值是"1"和“2”.
如果then通过return this来实现链式调用的话,因为是同一个实例,只能返回同样的结果。很显然这并不能满足我们的需求。
每个then注册的回调都返回了不同的结果作为下一个then回调的参数。因此在promie里面真正的链式调用是通过返回一个新的promise实现的。
promise真正的链式调用
真正的promise链式调用是指在当前promise达到fulfilled状态后,即开始下一个promise。即当前promise的then方法里面的返回值需要作为下一个promise的then回调方法的参数值。
首先我们这样修改then方法
then(resolveHandler,rejectedHandler){
let promise2;
//同理status为REJECTED和PENDING时也是返回一个promise2
if(this.status === RESOLVED){
promise2 = new Promise01((resolve,reject)=>{
//这便是then成功回调的返回值。我们需要把这个返回值最为下一个then成功回调的参数
let x = resolveHandler(this.resolvedValue);
//resolvePromise就是用来解析x和promise2之间的关系
resolvePromise(promise2,x,resolve,reject);
});
return promise2;
}
//同理status为REJECTED和PENDING时也是返回一个promose。在后面完整代码中可看
}那么关键部分就是resolvePromise怎么去处理当前promise的结果和后邻promise的关系。
首先我们考虑当前promise的then成功回调返回的是一个普通值,然后再举一反三。
resolvePromise(promise2,x,resolve,reject){
if(x!==null && (typeof x === "object" || typeof x === "function")){
//TODO
} else {
//改变promise2的resolvedValue值为上一个then的值
resolve(x);
}
}现在我们来看看特殊类型的返回值怎么处理?
function resolvePromise(promise2, x, resolve, reject) {
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then;
let called; // 防止成功后调用失败
if (typeof then === "function") {
// 如果then是函数我就认为x是promise
then.call(x, y => { // 如果y是promise就继续递归解析promise
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => { // 只要失败了就失败了
if (called) return;
called = true;
reject(r);
});
} else {
// then是一个普通对象,就直接成功调用成功即可
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(e);
}
} else {
//改变promise2的resolvedValue值为上一个then的值
resolve(x);
}
}完整代码
const PENDING = "pending";
const RESOLVED = "fulfilled";
const REJECTED = "rejected";
function resolvePromise(promise2, x, resolve, reject) {
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then;
let called; // 防止成功后调用失败
if (typeof then === "function") {// 如果then是函数我就认为x是promise
then.call(x, y => { // 如果y是promise就继续递归解析promise
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => { // 只要失败了就失败了
if (called) return;
called = true;
reject(r);
});
} else {
// then是一个普通对象,就直接成功调用成功即可
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(e);
}
} else {
//改变promise2的resolvedValue值为上一个then的值
resolve(x);
}}
class Promise01 {
constructor(excutor) {
if (typeof excutor !== "function") {
throw new Error("promise need a function");
}
// 默认状态是等待态
this.status = PENDING;
//存放成功的值
this.resolvedValue = null;
//存放失败的值
this.rejectedValue = null;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks = [];
let self = this;
let resolve = function(data) {
if (self.status === PENDING) {
self.resolvedValue = data;
self.status = RESOLVED;
self.onResolvedCallbacks.forEach(fn => fn(self.resolvedValue));
}
};
let reject = function(error) {
if (self.status === PENDING) {
self.rejectedValue = error;
self.status = REJECTED;
self.onRejectedCallbacks.forEach(fn => fn(self.rejectedValue));
}
};
try {// 执行时可能会发生异常
excutor(resolve, reject);
} catch (error) {// promise失败了
reject(error);
}
}
then(resolvedHandler, rejectedHandler) {
let promise2;
if (this.status === PENDING) { // 当前既没有完成 也没有失败
promise2 = new Promise((resolve, reject) => {
this.onResolvedCallbacks.push(() => {
let x = resolvedHandler(this.resolvedValue);
// resolvePromise可以解析x和promise2之间的关系
resolvePromise(promise2, x, resolve, reject);
});
this.onRejectedCallbacks.push(() => {
//失败的返回值,作为下一个then的失败回调的参数
let x = resolvedHandler(this.rejectedValue);
// resolvePromise可以解析x和promise2之间的关系
resolvePromise(promise2, x, resolve, reject);
});
});
} else if (this.status === RESOLVED) {// 当前成功状态
promise2 = new Promise((resolve, reject) => {
//成功的返回值,作为下一个then的成功回调的参数
let x = resolvedHandler(this.resolvedValue);
// resolvePromise可以解析x和promise2之间的关系
resolvePromise(promise2, x, resolve, reject);
});
} else if (this.status === REJECTED) {// 当前失败状态
promise2 = new Promise((resolve, reject) => {
//失败的返回值,作为下一个then的失败回调的参数
let x = resolvedHandler(this.rejectedValue);
// resolvePromise可以解析x和promise2之间的关系
resolvePromise(promise2, x, resolve, reject);
});
}
return promise2;
}}
let requestData1 = () => {
return new Promise01((resolve, reject) => {
setTimeout(() => {
resolve("1");
}, 1000);
});};
requestData1().then((data) => {
console.log(data);
return "2";}).then((data) => {
console.log(data);
});输出“1”和 "2"符合了预期结果。
Promise API 其他API实现
Promise.prototype.catch
Promise01.prototype.catch = (onRejected) => {
return Promise01.then(null, onRejected);
};Promise.prototype.finally
Promise01.prototyoe.finally = (cb) => {
return Promise01.then(cb,cb);
}Promise.race
Promise01.race = (...args)=>{
return new Promose01((resolve,reject)=>{
for(let i=0,l=args.length;i<l;i++){
let promise = args[i];
promise.then(resolve,reject);
}
});
}Promise.all
Promose01.all = (...args)=>{
return new Promose01((resolve,reject)=>{
let index = 0;
let res=[];
const processData = (i,data)=>{
res[index] = data;
index++;
if(index === args.length){
resolve(res);
}
};
for(let i =0,l=args.length;i<l;i++){
let promise = args[i];
promise.then((data)=>{
processData(i,data);
},reject);
}
});
};Promsie.resolve
Promise01.resolve = (val)=>{
return new Promise01((resolve,reject)=>resolve(val));
}Promise.reject
Promise01.reject = function(val) {
return new Promise01((resolve, reject) => reject(val))
;}Promise.deferred
Promise01.deferred = ()=>{
let dfd = {};
dfd = new Promise01((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};