PS:JS手写Promise方法的整理在下一篇文章
手写Promise的API(resolve,reject,then,catch,finally,all)_Eric加油学!的博客-CSDN博客
1、基础版Promise
首先,通过一个简单的Promise例子回顾其使用
const promise = new Promise((resolve, reject) => {
resolve('ok')
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
控制台输出 promise success: ok
- 首先我们在调用 Promise 时,会返回一个 Promise 对象
- 构建 Promise 对象时,需要传入一个 executor 函数,Promise 的主要业务流程都在 executor 函数中执行
- 如果运行在 excutor 函数中的业务执行成功了,会调用 resolve 函数;如果执行失败了,则调用 reject 函数
- Promise 的状态不可逆,同时调用 resolve 函数和 reject 函数,默认会采取第一次调用的结果
所以,我们可以得出一些Promise的基本特征:
- promise 有三个状态:
pending
,fulfilled,
rejected
new promise
时, 需要传递一个executor()
执行器,执行器立即执行executor
接受两个参数,分别是resolve
和reject
- promise 的默认状态是
pending
- promise 有一个
value
保存成功状态的值 - promise 有一个
reason
保存失败状态的值 - promise 只能从
pending
到rejected
, 或者从pending
到fulfilled
,状态一旦确认,就不会再改变 - promise 必须有一个
then
方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected - 如果调用 then 时,promise 已经成功,则执行
onFulfilled
,参数是promise
的value
- 如果调用 then 时,promise 已经失败,那么执行
onRejected
, 参数是promise
的reason
- 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 then 的失败的回调
onRejected
根据以上特征,就可以写一些基础版的Promise了
class Promise {
// Promise 等待态(初始状态)
static PENDING = 'pending';
// Promise 失败态
static REJECTED = 'rejected';
// Promise 成功态
static FULFILLED = 'fulfilled';
constructor(executor){
// 初始化 Promise 初始状态
this.status = Promise.PENDING;
// 定义 Promise 成功的值
this.value = undefined
// 定义 Promise 失败的原因
this.reason = undefined;
// 定义 resolve 函数
const resolve = (value) => {
if(this.status === Promise.PENDING){
this.status = Promise.FULFILLED;
this.value = value
}
}
// 定义 reject 函数
const reject = (reason) => {
if(this.status === Promise.PENDING){
this.status = Promise.REJECTED;
this.reason = reason
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled,onRejected){
if(this.status === Promise.FULFILLED){
onFulfilled(this.value)
}
if(this.status === Promise.REJECTED){
onRejected(this.reason)
}
}
}
module.exports = Promise;
对其进行测试:
const myPromise = require('./promise')
const promise = new myPromise((resolve, reject) => {
resolve('ok')
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
输出: promise success: ok
至此,一个简单的Promise就手写完毕了。不过目前只是实现了同步操作。如果在executor中有一个异步任务呢?
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
对于原生Promise,它的输出肯定是 在2秒后打印 promise success:ok
const myPromise = require('./promise')
const promise = new myPromise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
但对于我们刚才手写的基础版Promise而言,它是没有任何输出的
因为setTimeout是一个异步任务,executor执行到这发现是异步任务,暂时不去处理放入微队列,然后执行then时,promise实例的状态其实还是pending,所以不会执行任何操作。但确实2s后,它们的状态变为了fulfilled,我们可以稍微测试一下
const myPromise = require('./promise')
const promise = new myPromise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
setTimeout(()=>{
console.log(promise);
},2000)
2s后输出 Promise { status: 'fulfilled', value: 'ok', reason: undefined }
所以,在这个逻辑上,我们能否把成功和失败的回调先存储起来,当executor中的异步任务被执行时,触发resolve或reject再依次调用其回调呢?
class Promise {
// Promise 等待态(初始状态)
static PENDING = 'pending';
// Promise 失败态
static REJECTED = 'rejected';
// Promise 成功态
static FULFILLED = 'fulfilled';
constructor(executor){
// 初始化 Promise 初始状态
this.status = Promise.PENDING;
// 定义 Promise 成功的值
this.value = undefined
// 定义 Promise 失败的原因
this.reason = undefined;
// 定义存储 then 方法中成功的回调
this.onFulfilledCallbacks = [];
// 定义存储 then 方法中失败的回调
this.onRejectedCallbacks = [];
// 定义 resolve 函数
const resolve = (value) => {
if(this.status === Promise.PENDING){
this.status = Promise.FULFILLED;
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
// 定义 reject 函数
const reject = (reason) => {
if(this.status === Promise.PENDING){
this.status = Promise.REJECTED;
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled,onRejected){
if(this.status === Promise.FULFILLED){
onFulfilled(this.value)
}
if(this.status === Promise.REJECTED){
onRejected(this.reason)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
module.exports = Promise;
我们的思路是:
1、既然执行到then时,由于有异步任务,所以状态仍是 pending,那我们先对其状态进行判断 if(this.status === Promise.PENDING) ,对resolve和reject的回调进行存储
2、定义存储then中resolve和reject的回调,考虑到可能不只会有一个then方法,所以我们应该定义为 数组
3、当 执行到异步任务 时,他们的状态进行变化,我们在相应的resolve和reject函数中对数组里存储的各个回调依次调用
进行测试:
const myPromise = require('./promise')
const promise = new myPromise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
2s后输出 promise success: ok
此外,Promise还有一个优势在于其链式调用,它可以让我们使用Promise时,当then函数中,return了一个值,我们可以在下一个then中获取到。例如: promise.then().then()
其实这种写法也等同于
const promise2 = promise.then((value) => {
},(reason) => {
})
promise2.then(......)
所以先对原生的Promise进行试验:
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
2s后输出:
promise success: ok
promise2 success: undefined
因为我们没有写promise中then方法的返回值,而没有写的话,函数的返回值默认是undefined
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return 123
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
如果promise的then有返回值,则输出为
promise success: ok
promise2 success: 123
class Promise {
// Promise 等待态(初始状态)
static PENDING = 'pending';
// Promise 失败态
static REJECTED = 'rejected';
// Promise 成功态
static FULFILLED = 'fulfilled';
constructor(executor){
// 初始化 Promise 初始状态
this.status = Promise.PENDING;
// 定义 Promise 成功的值
this.value = undefined
// 定义 Promise 失败的原因
this.reason = undefined;
// 定义存储 then 方法中成功的回调
this.onFulfilledCallbacks = [];
// 定义存储 then 方法中失败的回调
this.onRejectedCallbacks = [];
// 定义 resolve 函数
const resolve = (value) => {
if(this.status === Promise.PENDING){
this.status = Promise.FULFILLED;
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
// 定义 reject 函数
const reject = (reason) => {
if(this.status === Promise.PENDING){
this.status = Promise.REJECTED;
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled,onRejected){
return new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
const x = onFulfilled(this.value)
resolve(x)
}
if(this.status === Promise.REJECTED){
onRejected(this.reason)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
const x = onFulfilled(this.value)
resolve(x);
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
})
}
}
module.exports = Promise;
所以,只需要在then函数里面,返回一个新的Promise即可,并且获取成功回调函数的返回值,暴露给resolve
测试后:
promise success: ok
promise2 success: 123
再看原生Promise对于失败的处理,promise状态变为rejected,promise2走的是 成功的回调。
只有promise中抛错或者是返回一个rejected状态的Promise,promise2才会走失败的回调
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return 123
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
promise fail: ok
promise2 success: undefined
如果我们暂时先不管promise里面抛错或者返回rejected的Promise,那其实和成功一样,我们获取回调返回值并暴露给resolve即可。
then(onFulfilled,onRejected){
return new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
const x = onFulfilled(this.value)
resolve(x)
}
if(this.status === Promise.REJECTED){
const x = onRejected(this.reason)
resolve(x)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
const x = onFulfilled(this.value)
resolve(x);
})
this.onRejectedCallbacks.push(() => {
const x = onRejected(this.reason)
resolve(x);
})
}
})
}
再考虑一步,如果promise里面抛错了,要如何处理,其实就是可以用try catch捕获一下,一旦抛错,直接reject即可
then(onFulfilled,onRejected){
return new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
try {
const x = onFulfilled(this.value)
resolve(x)
} catch (e) {
reject(e)
}
}
if(this.status === Promise.REJECTED){
try {
const x = onRejected(this.reason)
resolve(x)
} catch (e) {
reject(e)
}
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
try {
const x = onFulfilled(this.value)
resolve(x);
} catch (e) {
reject(e)
}
})
this.onRejectedCallbacks.push(() => {
try {
const x = onRejected(this.reason)
resolve(x);
} catch (e) {
reject(e)
}
})
}
})
}
至此,promise里面抛错和返回普通值 已经处理好了。 那如果promise里面返回new Promise呢
原生Promise的执行效果如下
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return new Promise((resolve,reject) => {
resolve('ok2')
})
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
promise success: ok
promise2 success: ok2
而目前我们的myPromise的输出是如下的:
promise success: ok
promise2 success: Promise {
status: 'fulfilled',
value: 'ok2',
reason: undefined,
onFulfilledCallbacks: [],
onRejectedCallbacks: []
}因为我们直接获取了它的返回值记为x,并resolve(x)。所以可以进行一些处理逻辑
由于这些处理逻辑基本都一样,所以可以提出去,单独写一个函数
const resolvePromise = (promise2, x, resolve, reject) => {
}
这里接收4个参数,分别是 我们要返回的new Promise2,promise返回的promise,要返回的resolve和reject回调
所以可以这么写(其余的几个if判断里的处理也一样)
then(onFulfilled,onRejected){
return new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
这里的promise2是哪里来的呢?其实就是外层要return的这个new Promise,所以我们可以先定义,再最后return
then(onFulfilled,onRejected){
const promise2 = new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}
......
}
return promise2
但使用这个promise2,是在promise2的定义体内部的,咋获取?
可以使用setTimeout,把它变成异步就可以获取到promise2了
then(onFulfilled,onRejected){
const promise2 = new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
即
then(onFulfilled,onRejected){
const promise2 = new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
}
if(this.status === Promise.REJECTED){
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
})
}
})
return promise2
}
所以,接下来就只要完成resolvePromise方法即可
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成的情况, 直接抛错
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if((typeof x === 'object' && x !== null) || typeof x === 'function'){
try { // 这里防止返回的对象里面,调用then会报错的情况
const then = x.then;
if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象
then.call(x, (y) => {
resolve(y)
},(r) => {
reject(r)
})
} else { // 普通对象,上面有then属性而已
resolve(x)
}
} catch (e) {
reject(e)
}
}else{
// 不是对象也不是函数,那就是普通值,直接resolve
resolve(x)
}
}
class Promise {
// Promise 等待态(初始状态)
static PENDING = 'pending';
// Promise 失败态
static REJECTED = 'rejected';
// Promise 成功态
static FULFILLED = 'fulfilled';
constructor(executor){
// 初始化 Promise 初始状态
this.status = Promise.PENDING;
// 定义 Promise 成功的值
this.value = undefined
// 定义 Promise 失败的原因
this.reason = undefined;
// 定义存储 then 方法中成功的回调
this.onFulfilledCallbacks = [];
// 定义存储 then 方法中失败的回调
this.onRejectedCallbacks = [];
// 定义 resolve 函数
const resolve = (value) => {
if(this.status === Promise.PENDING){
this.status = Promise.FULFILLED;
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
// 定义 reject 函数
const reject = (reason) => {
if(this.status === Promise.PENDING){
this.status = Promise.REJECTED;
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled,onRejected){
const promise2 = new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
}
if(this.status === Promise.REJECTED){
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
})
}
})
return promise2
}
}
module.exports = Promise;
这时,进行测试,就正常了
const myPromise = require('./promise')
const promise = new myPromise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return new Promise((resolve,reject) => {
resolve('ok2')
})
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
promise success: ok
promise2 success: ok2
但如果resolve里面继续new Promise呢,目前只做了一层的处理,所以我们还要递归解析
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return new Promise((resolve,reject) => {
resolve(new Promise((resolve,reject)=>{
resolve('ok2')
}))
})
}, (reason) => {
console.log("promise fail:", reason);
})
这样就可以处理嵌套的new Promise情况了
还没结束,如果在promise的return中,连续执行回调,它也会连续执行
const Promise = require('./promise')
const promise = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('ok')
},2000)
});
const promise2 = promise.then((value) => {
console.log("promise success:", value);
return {
then(onFulfilled,onRejected){
throw new Error(onFulfilled('ok'))
}
}
}, (reason) => {
console.log("promise fail:", reason);
})
promise2.then((value)=>{
console.log("promise2 success:", value);
},(reason)=>{
console.log("promise2 fail:", reason);
})
这样肯定是不对的,不可能既成功又失败。 所以应该只让它执行一次
所以可以设置一个变量called,分别在成功和失败的执行中进行控制
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成的情况, 直接抛错
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if((typeof x === 'object' && x !== null) || typeof x === 'function'){
let called = false;
try { // 这里防止返回的对象里面,调用then会报错的情况
const then = x.then;
if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象
then.call(x, (y) => {
if(called) return;
called = true;
resolvePromise(promise2, y, resolve, reject)
},(r) => {
reject(r)
})
} else { // 普通对象,上面有then属性而已
resolve(x)
}
} catch (e) {
if(called) return;
called = true;
reject(e)
}
}else{
// 不是对象也不是函数,那就是普通值,直接resolve
resolve(x)
}
}
至此,就实现了Promise最为关键的部分: then的链式调用
完整代码如下:
const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成的情况, 直接抛错
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if((typeof x === 'object' && x !== null) || typeof x === 'function'){
let called = false;
try { // 这里防止返回的对象里面,调用then会报错的情况
const then = x.then;
if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象
then.call(x, (y) => {
if(called) return;
called = true;
console.log('test');
resolvePromise(promise2, y, resolve, reject)
},(r) => {
reject(r)
})
} else { // 普通对象,上面有then属性而已
resolve(x)
}
} catch (e) {
if(called) return;
called = true;
console.log('test');
reject(e)
}
}else{
// 不是对象也不是函数,那就是普通值,直接resolve
resolve(x)
}
}
class Promise {
// Promise 等待态(初始状态)
static PENDING = 'pending';
// Promise 失败态
static REJECTED = 'rejected';
// Promise 成功态
static FULFILLED = 'fulfilled';
constructor(executor){
// 初始化 Promise 初始状态
this.status = Promise.PENDING;
// 定义 Promise 成功的值
this.value = undefined
// 定义 Promise 失败的原因
this.reason = undefined;
// 定义存储 then 方法中成功的回调
this.onFulfilledCallbacks = [];
// 定义存储 then 方法中失败的回调
this.onRejectedCallbacks = [];
// 定义 resolve 函数
const resolve = (value) => {
if(this.status === Promise.PENDING){
this.status = Promise.FULFILLED;
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
// 定义 reject 函数
const reject = (reason) => {
if(this.status === Promise.PENDING){
this.status = Promise.REJECTED;
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled,onRejected){
const promise2 = new Promise((resolve, reject)=>{
if(this.status === Promise.FULFILLED){
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
}
if(this.status === Promise.REJECTED){
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
}
if(this.status === Promise.PENDING){
this.onFulfilledCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
},0)
})
}
})
return promise2
}
}
module.exports = Promise;
剩下的就是Promise的一些其他方法:resolve、reject、catch、finally、all等
手写Promise的API(resolve,reject,then,catch,finally,all)_Eric加油学!的博客-CSDN博客
如有帮助,三连一下呀