参考文章:《Promise,从入门到放弃》
为了方便比较与原装的
Promise
区别,手写的Promise
被命名为iPromise
。
实现本体
- 首先,
Promise
是一个类,接收一个函数executor
作为构造函数,该函数接受两个函数作为参数:resolve
和reject
(Promise
自带,并不需要使用者手动部署),且立即(同步)执行。
Promise
对象的promiseResult
属性存储执行的结果,promiseState
属性存储状态。
Promise
有三种状态:pending
(准备中)、fulfilled
(满足)和rejected
(拒绝)。初始状态是pending
。
class iPromise {
constructor(executor) {
// 存储promise结果
this.promiseResult = undefined;
// 存储promise的状态
this.promiseState = 'pending';
// 立即执行executor
executor(resolve, reject);
}
}
-
resolve
方法的作用是将执行所得的结果赋值给promiseResult
,并将promiseState
由pending
变为fulfilled
。reject
方法基本一样,只是将promiseState
由pending
变为rejected
。
promise
对象的状态变化只能变化一次;
executor
执行出现错误,也会触发reject
函数。
class iPromise {
constructor(executor) {
// 存储promise结果
this.promiseResult = undefined;
// 存储promise的状态
this.promiseState = 'pending';
// resolve方法,将promiseState变为fulfilled,并修改promiseResult
const resolve = (value) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为fulfilled
this.promiseState = 'fulfilled';
// 将value作为promiseResult
this.promiseResult = value;
}
// reject方法,将promiseState变为rejected,并修改promiseResult
const reject = (error) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为rejected
this.promiseState = 'rejected';
// 将error作为promiseResult
this.promiseResult = error;
}
// 立即执行executor
// executor函数执行出现错误,会调用reject方法
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
实现then方法
-
Promise.then()
方法接收1~2个回调函数作为参数,返回一个新的Promise
对象(下文中如果没有特殊说明,Promise
对象都指原Promise
对象)以支持链式调用。
返回的新
Promise
对象的参数必须使用箭头函数()=>{}
,否则会造成this
指向错误的问题。当然,你也可以采取let self = this;
存储this
然后传入的形式,不过有点多此一举。
class iPromise {
constructor(executor){
// 构造函数
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
// ...
})
}
}
- 根据
promiseResult
的值不同,分为两种情况:当其为Promise
对象时,递归执行它的then
方法;当其为其他类型,直接调用resolve
方法。
class iPromise {
constructor(executor){
// ...
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
/*
* 回调处理函数
* 这里也请记得用箭头函数,this要穿透几层
* 箭头函数就用几层
*/
const handleCallback = (callback) => {
try {
let res = callback(this.promiseResult);
// 若返回值是promise对象
if (res instanceof Promise) {
res.then(val => resolve(val), err => reject(err));
} else {
// 若不是
resolve(res);
}
} catch (error) {
reject(error);
}
}
})
}
}
- 根据
promiseState
的值来确定应该执行哪个回调函数:
class iPromise {
constructor(executor){
// ...
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
/*
* 回调处理函数
* 这里也请记得用箭头函数,this要穿透几层
* 箭头函数就用几层
*/
const handleCallback = (callback) => {
try {
let res = callback(this.promiseResult);
// 若返回值是promise对象
if (res instanceof Promise) {
res.then(val => resolve(val), err => reject(err));
} else {
// 若不是
resolve(res);
}
} catch (error) {
reject(error);
}
}
// promiseState为fulfilled时调用onResolved
if (this.promiseState === "fulfilled") {
handleCallback(onResolved);
}
// promiseState为rejected时调用onRejected
if (this.promiseState === "rejected") {
handleCallback(onRejected);
}
})
}
}
- 因为异步任务的问题,并且支持多个回调,所以我们需要对回调函数采用数组进行存储,所以引入了新的变量:
callbackList
:
class iPromise {
constructor(executor) {
// 存储promise结果
this.promiseResult = undefined;
// 存储promise的状态
this.promiseState = 'pending';
// 存储所有的回调函数
this.callbackList = [];
// resolve方法,将promiseState变为fulfilled,并修改promiseResult
const resolve = (value) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为fulfilled
this.promiseState = 'fulfilled';
// 将value作为promiseResult
this.promiseResult = value;
// 异步执行所有回调函数
this.callbackList.forEach(cb => cb.onResolved(value));
}
// reject方法,将promiseState变为rejected,并修改promiseResult
const reject = (error) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为rejected
this.promiseState = 'rejected';
// 将error作为promiseResult
this.promiseResult = error;
// 异步执行所有回调函数
this.callbackList.forEach(cb => cb.onRejected(error));
}
// 立即执行executor
// executor函数执行出现错误,会调用reject方法
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
/*
* 回调处理函数
* 这里也请记得用箭头函数,this要穿透几层
* 箭头函数就用几层
*/
const handleCallback = (callback) => {
try {
let res = callback(this.promiseResult);
// 若返回值是promise对象
if (res instanceof Promise) {
res.then(val => resolve(val), err => reject(err));
} else {
// 若不是
resolve(res);
}
} catch (error) {
reject(error);
}
}
// promiseState为fulfilled时调用onResolved
if (this.promiseState === "fulfilled") {
handleCallback(onResolved);
}
// promiseState为rejected时调用onRejected
if (this.promiseState === "rejected") {
handleCallback(onRejected);
}
/*
* 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
* 所以要保存回调函数
* 因为promise实例可以指定多个回调,于是采用数组
*/
if (this.promiseState === "pending") {
this.callbackList.push({
onResolved: () => {
handleCallback(onResolved)
},
onRejected: () => {
handleCallback(onRejected)
}
})
}
})
}
}
catch方法
catch
方法主要需要做到的就是异常穿透:
当使用
promise
的then
进行链式调用时,可以在最后指定失败的回调。前面的任何错误都会在最后传到失败的回调中去处理,除非在中途被失败回调函数(onRejected
)处理了。
// promise对象的异常穿透
let p1 = Promise.resolve(1);
p1.then((value)=>{
console.log(11);
}).then((value)=>{
throw 'err';
}).then((value)=>{
console.log(22);
}).catch(err=>{
console.log(err);
})
// 最终输出:
// 11
// err
要实现catch
,我们可以直接调用iPromise.then
方法,但不传入onResolve
方法。
同时,我们需要给then
中的onResolve
和onRejected
赋初始值,顺便避免了传入undefined
或其他非函数值而报错:
class iPromise {
constructor(executor) {
// 构造函数
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
// 处理异常穿透,并设置默认值以避免程序出错
if(typeof onResolved !== 'function') {
onResolve = (val) => val;
}
if(typeof onRejected !== 'function') {
onRejected = (err) => {
throw err;
}
}
return new iPromise((resolve, reject) => {
// ...调用回调函数
})
}
// catch方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
}
Promise.resolve方法
Promise.resolve
方法返回成功或者失败的Promise
对象。如果传入的参数为非Promise
类型的对象,则返回的结果为成功的Promise
对象。如果传入的参数为Promise
对象,则参数Promise
返回的结果就是 Promise.resolve
返回的结果。
let promiseA = Promise.resolve(1);
// 比如这时return 一个[[PromiseResult]]的值为err的Promise对象。
let PromiseB = Promise.resolve(new Promise((resolve,reject)=>{
reject('err');
})
实现它,我们需要用到静态方法:
class iPromise {
constructor(executor) {
// 构造函数
}
// ...其他方法
// 静态方法只能通过类本身来调用
static resolve(value) {
return new iPromise((resolve, reject) => {
// 如果是iPromise对象
if (value instanceof iPromise) {
value.then(val => resolve(val), err => reject(err));
} else {
resolve(value);
}
})
}
}
Promise.reject方法
Promise.reject
方法返回一个失败的Promise
对象,promiseResult
的值为Promise.reject
的参数。
有多失败?大概像我一样失败。
let PromiseA = Promise.reject(new Promise((resolve,reject)=>{
resolve('err');
})
// 无论传入是啥,就返回一个失败的Promise对象,[[PromiseResult]]的值为 Promise.reject的参数
实现:
class iPromise {
constructor(executor) {
// 构造函数
}
// ...其他方法
// 静态方法只能通过类本身来调用
static reject(error) {
return new iPromise((resolve, reject) => {
reject(error);
})
}
}
Promise.all方法
Promise.all
方法接收的参数是由n个Promise
对象的数组。返回新的Promise
对象,只有所有的Promise
对象都成功才成功,返回的对象的promiseResult
为包含所有Promise
对象的数组。只要有一个失败了就直接失败,返回的对象的promiseResult
为失败的Promise
对象的执行结果。
class iPromise {
constructor(executor) {
// 构造函数
}
// ...其他方法
static all(promiseArrays) {
return new iPromise((resolve, reject) => {
// 用以存储执行的结果
let results = [];
let length = promiseArrays.length;
promiseArrays.forEach((promiseObj, index, promiseArrays) => {
promiseObj.then((val) => {
results.push(val);
// 由于是多个异步任务的关系,需要判断是否都执行完毕
if (results.length === length) {
resolve(results);
}
}, err => {
// 如有错误,则reject
reject(err);
});
})
})
}
}
Promise.race方法
Promise.race方法接收的参数是由n个Promise对象的数组。返回新的Promise
对象,第一个完成的Promise的结果状态就是最终结果的状态。
你可能会问:那不铁定第一个Promise对象是第一个完成的吗?
这是因为我们的最重要的功能还没做:异步。
class iPromise {
constructor(executor) {
// 构造函数
}
// ...其他方法
// race方法
static race(promiseArrays) {
return new iPromise((resolve, reject) => {
promiseArrays.forEach(promiseObj => {
promiseObj.then(val => {
resolve(val);
}, err => {
reject(err);
});
})
})
}
}
加点细节—由同步到异步
使用setTimeout
将其变为异步任务。
setTimeout
只能将任务变更为宏观异步任务。原装的Promise
是微观异步任务。
class iPromise {
constructor(executor) {
// 存储promise结果
this.promiseResult = undefined;
// 存储promise的状态
this.promiseState = 'pending';
// 存储所有的回调函数
this.callbackList = [];
// resolve方法,将promiseState变为fulfilled,并修改promiseResult
const resolve = (value) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为fulfilled
this.promiseState = 'fulfilled';
// 将value作为promiseResult
this.promiseResult = value;
// 异步执行所有回调函数
setTimeout(()=>{
this.callbackList.forEach(cb => cb.onResolved(value));
})
}
// reject方法,将promiseState变为rejected,并修改promiseResult
const reject = (error) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
// 将promiseState变为rejected
this.promiseState = 'rejected';
// 将error作为promiseResult
this.promiseResult = error;
// 异步执行所有回调函数
setTimeout(()=>{
this.callbackList.forEach(cb => cb.onRejected(error));
})
}
// 立即执行executor
// executor函数执行出现错误,会调用reject方法
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
//处理异常穿透并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传
if (typeof onRejected !== 'function') {
onRejected = err => {
throw err;
}
}
if (typeof onResolved !== 'function') {
onResolved = val => val;
}
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
/*
* 回调处理函数
* 这里也请记得用箭头函数,this要穿透几层
* 箭头函数就用几层
*/
const handleCallback = (callback) => {
try {
let res = callback(this.promiseResult);
// 若返回值是promise对象
if (res instanceof iPromise) {
res.then(val => resolve(val), err => reject(err));
} else {
// 若不是
resolve(res);
}
} catch (error) {
reject(error);
}
}
// promiseState为fulfilled时调用onResolved
if (this.promiseState === "fulfilled") {
setTimeout(() => {
handleCallback(onResolved);
});
}
// promiseState为rejected时调用onRejected
if (this.promiseState === "rejected") {
setTimeout(() => {
handleCallback(onRejected);
});
}
/*
* 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
* 所以要保存回调函数
* 因为promise实例可以指定多个回调,于是采用数组
*/
if (this.promiseState === "pending") {
this.callbackList.push({
onResolved: () => {
handleCallback(onResolved)
},
onRejected: () => {
handleCallback(onRejected)
}
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
static resolve(value) {
return new iPromise((resolve, reject) => {
if (value instanceof iPromise) {
value.then(val => resolve(val), err => reject(err));
} else {
resolve(value)
}
})
}
static reject(error) {
return new iPromise((resolve, reject) => {
reject(error);
})
}
static all(promiseArrays) {
return new iPromise((resolve, reject) => {
// 用以存储执行的结果
let results = [];
let length = promiseArrays.length;
promiseArrays.forEach((promiseObj, index, promiseArrays) => {
promiseObj.then((val) => {
results.push(val);
// 由于是多个异步任务的关系,需要判断是否都执行完毕
if (results.length === length) {
resolve(results);
}
}, err => {
// 如有错误,则reject
reject(err);
});
})
})
}
static race(promiseArrays) {
return new iPromise((resolve, reject) => {
promiseArrays.forEach(promiseObj => {
promiseObj.then(val => {
resolve(val);
}, err => {
reject(err);
});
});
})
}
}
总结
......没啥好说的,从上到下敲一遍,不说运用自如,怎么也得是一脸懵逼吧。