手写Promise
Promise的声明
首先,promise
肯定是一个类,我们就用class
来声明。
- 由于
new Promise((resolve, reject)=>{})
,所以传入一个参数(函数),promisesA+规范里叫他executor
,传入就执行。 -
executor
里面有两个参数,一个叫resolve
(成功),一个叫reject
(失败)。 - 由于
resolve
和reject
可执行,所以都是函数,我们用let
声明。
class Promise {
// 构造器
constructor(executor) {
// 成功
let resolve = () => { };
// 失败
let reject = () => { };
// 立即执行
executor(resolve, reject);
}
}
解决基本状态
promisesA+
规范对Promise
有规定:
-
Promise
存在三个状态(state
):pending
、fulfilled
、rejected
-
pending
(等待态)为初始态,并可以转化为fulfilled
(成功态)和rejected
(失败态) - 成功时,不可转为其他状态,且必须有一个不可改变的值(
value
) - 失败时,不可转为其他状态,且必须有一个不可改变的原因(
reason
) -
new Promise((resolve, reject)=>{resolve(value)})
,resolve
为成功,接收参数value
,状态改变为fulfilled
,不可再次改变 -
new Promise((resolve, reject)=>{reject(reason)})
,reject
为失败,接收参数reason
,状态改变为rejected
,不可再次改变 - 若是
executor
函数报错,直接执行reject()
于是乎,我们获得以下代码:
class Promise {
constructor(executor) {
// 初始化state为等待态
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的原因
this.reason = undefined;
let resolve = value => {
// state改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state转化为成功态
this.state = 'fulfilled';
// 储存成功的值
this.value = value;
}
};
let reject = reason => {
// state改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected';
// 储存失败的原因
this.reason = reason;
}
};
// 如果executor执行报错,直接执行reject
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
then方法
promisesA+
规范规定:Promise
有一个叫做then
的方法,里面有两个参数:onFulfilled, onRejected
,成功有成功的值,失败有失败的原因。
- 当状态
state
为fulfilled
,则执行onFulfilled
,传入this.value
。当状态state
为rejected
,则执行onRejected
,传入this.reason
-
onFulfilled, onRejected
如果他们是函数,则必须分别在fulfilled
,rejected
后被调用,value
或reason
依次作为他们的第一个参数
class Promise {
constructor(executor) {...}
// then 方法 有两个参数onFulfilled onRejected
then(onFulfilled, onRejected) {
// 状态为fulfilled,执行onFulfilled,传入成功的值
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
// 状态为rejected,执行onRejected,传入失败的原因
if (this.state === 'rejected') {
onRejected(this.reason);
};
}
}
解决异步实现
现在基本可以实现简单的同步代码,但是当resolve
在setTomeout
内执行,then
时state
还是pending
等待状态 我们就需要在then
调用的时候,将成功和失败存到各自的数组,一旦reject
或者resolve
,就调用它们。
类似于发布订阅,先将then
里面的两个函数储存起来,由于一个promise
可以有多个then
,所以存在同一个数组内。
// 多个then的情况
let p = new Promise();
p.then();
p.then();
成功或者失败时,forEach调用它们。
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放法数组
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve执行,调用成功数组的函数
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject执行,调用失败数组的函数
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 当状态state为pending时
if (this.state === 'pending') {
// onFulfilled传入到成功数组
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected传入到失败数组
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
解决链式调用
我门常常用到new Promise().then().then()
,这就是链式调用,用来解决回调地狱。
为了达成链式,我们默认在第一个then
里返回一个promise
。promisesA+
规范规定了一种方法,就是在then
里面返回一个新的promise
,称为promise2
:promise2 = new Promise((resolve, reject)=>{})
- 将这个
promise2
返回的值传递到下一个then
中 - 如果返回一个普通的值,则将普通的值传递给下一个
then
中
当我们在第一个then
中return
了一个参数(参数未知,需判断)。这个return
出来的新的promise
就是onFulfilled()
或onRejected()
的值。
promisesA+
规范则规定onFulfilled()
或onRejected()
的值,即第一个then
返回的值,叫做x
,判断x
的函数叫做resolvePromise
。
- 首先,要看
x
是不是promise
- 如果是
promise
,则取它的结果,作为新的promise2
成功的结果 - 如果是普通值,直接作为
promise2
成功的结果 - 所以要比较
x
和promise2
-
resolvePromise
的参数有promise2
(默认返回的promise
)、x
(我们自己return
的对象)、resolve
、reject
-
resolve
和reject
是promise2
的
class Promise {
constructor(executor) { ... }
then(onFulfilled, onRejected) {
// 声明返回的promise2
let promise2 = new Promise((resolve, reject)=>{
if (this.state === 'fulfilled') {
let x = onFulfilled(this.value);
// resolvePromise函数,处理自己return的promise和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'rejected') {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(()=>{
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.onRejectedCallbacks.push(()=>{
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise,完成链式
return promise2;
}
}
完成resolvePromise函数
promisesA+
规范规定了一段代码,让不同的promise
代码互相套用,叫做resolvePromise
。
如果x === promise2
,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误。
let p = new Promise(resolve => {
resolve(0);
});
var p2 = p.then(data => {
// 循环引用,自己等待自己完成,一辈子完不成
return p2;
})
- 判断
x
:
-
x
不能是null
-
x
是普通值 直接resolve(x)
-
x
是对象或者函数(包括promise
),let then = x.then
- 当
x
是对象或者函数(默认promise
)
- 声明了
then
- 如果取
then
报错,则走reject()
- 如果
then
是个函数,则用call
执行then
,第一个参数是this
,后面是成功的回调和失败的回调 - 如果成功的回调还是
pormise
,就递归继续解析
- 成功和失败只能调用一个,所以设定一个
called
来防止多次调用
function resolvePromise(promise2, x, resolve, reject){
// 循环引用报错
if(x === promise2){
// reject报错
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止多次调用
let called;
// x不是null 且x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+规定,声明then = x的then方法
let then = x.then;
// 如果then是函数,就默认是promise了
if (typeof then === 'function') {
// 就让then执行 第一个参数是this 后面是成功的回调 和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve的结果依旧是promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就失败了
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(e);
}
} else {
resolve(x);
}
}
解决其他问题
-
promisesA+
规范规定onFulfilled, onRejected
都是可选参数,如果他们不是函数,必须被忽略
-
onFulfilled
返回一个普通的值,成功时直接等于value => value
-
onRejected
返回一个普通的值,失败时如果直接等于value => value
,则会跑到下一个then
中的onFulfilled
中,所以直接扔出一个错误reason => throw err
-
promisesA+
规范规定onFulfilled
或onRejected
不能同步被调用,必须异步调用。我们就用setTimeout
解决异步问题
- 如果
onFulfilled
或onRejected
报错,则直接返回reject()
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成链式
return promise2;
}
}
catchresolve、reject、race和all方法
class Promise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
return promise2;
}
catch(fn){
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if(called)return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}