Promise基础相关
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。Promise-Javascript | MDN
这里是promise的规范文档 Promise A+规范
promise在前端的工作学习以及面试中都是经常出现的知识,仅仅熟练使用他对我来说已经无法满足我的好奇心,有必要亲自实现它一下,开始吧!!!
手动实现
实现思路
- promise接受一个立即执行的函数,该函数有两个回调参数,resolve,reject
- promise有三个状态,pending, fulfilled, rejected, 且只能由pending转为其他两中状态
- proise的then方法,可以拿到变化后的promise的状态,并返回一个新的promise对象
- then方法中对回调值的处理函数的实现
- promise的静态方法,resolve,reject,race,all
新建TjfPromise类,传入回调参数并立即执行
// 定义promise的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class TjfPromise{
constructor(callback){
this.status = PENDING // 初始态为pending
this.value = null
this.reason = null
try{
// promise中传入的函数是立即执行的,这里注意调用时候的this指向
// promise中的resolve,reject函数调用的是内部实现的函数
callback(this.resolve.bind(this), this.reject.bind(this))
}catch(error){
this.reject(error)
}
}
// promise的状态只能由pending --> fulfilled 或者 pending --> rejected
// 调用resolve方法的时候,status变为fulfilled
resolve(value){
if(this.status === PENDING){
this.status = FULFILLED
this.value = value
}
}
// 调用reject方法的时候,status变为rejected
reject(reason){
if(this.status === PENDING){
this.status = REJECTED
this.reason = reason
}
}
}
初步实现then方法
class TjfPromise {
......
then(onFulfilled, onRejected){
switch(this.status){
case FULFILLED:
onFulfilled(this.value)
break
case REJECTED:
onRejected(this.reason)
break
}
}
}
拿两个小例子测试一下目前的代码
new TjfPromise((resolve, reject) => {
resolve(11)
}).then(value => console.log(value))
结果打印出来11,说明目前初步实现。
但是这里有三个问题,第一个问题是,then方法里面只对fulfilled和rejected两种状态做了判断,pending的时候,也就是promise中的代码没有立即执行,也就是异步的时候没有处理,毕竟promise主要就是来处理异步任务的。
第二个问题是多次调用then方法的时候(非链式调用),后面的then调用的时候,前面的then的内容可能还没有执行,需要存储起来
第三个问题是then函数是支持链式调用的,promise A+ 规范里面说then必须返回一个promise对象
我们先解决第一个问题,对异步调用的支持
then方法对异步的支持
class TjfPromise{
constructor(callback){
this.status = PENDING
this.value = null
this._status = PENDING // 新增变量,配合status的set,get
this.reason = null
// 新增两个变量用来存储pending时的回调函数
this.FULFILLED_CALLBACK = null
this.REJECTED_CALLBACK = null
try{
callback(this.resolve.bind(this), this.reject.bind(this))
}catch(error){
this.reject(error)
}
}
get status(){ // 新增get
return this._status
}
set status(newStatus){ // 新增set
this._status = newStatus // 用_status防止嵌套触发set,陷入死循环
if(newStatus === FULFILLED){ // 状态改变的时候立即调用存储的回调
this.FULFILLED_CALLBACK(this.value)
}
if(newStatus === REJECTED){
this.REJECTED_CALLBACK(this.reason)
}
}
resolve(value){
if(this.status === PENDING){
this.value = value // 赋值要在状态改变的前面,顺序不能变
this.status = FULFILLED
}
}
reject(reason){
if(this.status === PENDING){
this.reason = reason
this.status = REJECTED
}
}
then(onFulfilled, onRejected){
switch(this.status){
case FULFILLED:
onFulfilled(this.value)
break
case REJECTED:
onRejected(this.reason)
break
case PENDING: // pending的时候先将回调函数存储起来,等待调用
this.FULFILLED_CALLBACK = onFulfilled
this.REJECTED_CALLBACK = onRejected
}
}
}
我们来测试一下现在的代码
new TjfPromise((resolve, reject) => {
setTimeout(() => {
resolve(11)
}, 1000)
}).then((value) => console.log(value))
延时了一秒之后打印了11,说明没有问题。下面解决第二个问题,then的多次调用问题
then方法对多次调用的支持
我们需要对刚刚的代码进行一些更改,把回调放在一个数组里面存储即可
class TjfPromise{
constructor(){
// 把刚刚用来存储pending时的回调函数的变量改造为两个数组
this.FULFILLED_CALLBACK_LIST = []
this.REJECTED_CALLBACK_LIST = []
}
set status(newStatus){ // setter 中做一些更改
this._status = newStatus
if(newStatus === FULFILLED){ // 依次执行所有保存的回调
this.FULFILLED_CALLBACK_LIST.forEach( callback => callback(this.value))
}
if(newStatus === REJECTED){
this.REJECTED_CALLBACK_LIST.forEach( callback => callback(this.reason))
}
}
then(onFulfilled, onRejected){ // 对then方法的改造
switch(this.status){
case FULFILLED:
onFulfilled(this.value)
break
case REJECTED:
onRejected(this.reason)
break
case PENDING: // pending的时候先将回调函数存储起来,等待调用
this.FULFILLED_CALLBACK_LIST.push(onFulfilled)
this.REJECTED_CALLBACK_LIST.push(onRejected)
}
}
测试一下
const promise = new TjfPromise((resolve, reject) => {
setTimeout(() => {
resolve(11)
}, 1000)
})
promise.then( value => console.log(1,value))
promise.then( value => console.log(2,value))
promise.then( value => console.log(3,value))
打印结果
1 11
2 11
3 11
没有问题,第二个问题解决了,下面就是最麻烦的第三个问题,then函数的返回
then方法的完善
这里的实现按照promise A+文档的要求来实现,比较繁琐
then方法中对回调参数的判断
then方法如果传入的参数不是或者没有传值,应该做处理为一个直接返回的函数
class TjfPromise{
......
then(onFulfiled, onRejected){
// 对传入的参数进行处理
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
const realOnFulfilled = this.isFunction(onRejected) ? onRejected : reason => {throw reason}
}
isFunction(func){ // 新增验证是否为函数
return typeof func === 'function'
}
}
then方法应该返回一个promise
class TjfPromise{
......
then(onFulfilled, onRejected){
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => {throw reason}
const promise2 = new TjfPromise((resolve, reject) => {
switch(this.status){
case FULFILLED:
realOnFulfilled(this.value)
break
case REJECTED:
realOnRejected(this.reason)
break
case PENDING: // pending的时候先将回调函数存储起来,等待调用
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
this.REJECTED_CALLBACK_LIST.push(realOnRejected)
}
})
return promise2
}
}
这里需要对realOnfulfilled的值做判断,这里我们开始实现resolvePromise函数
then方法里面加入resolvePromise函数,先对realOnFulfilled处理
class TjfPromise{
......
then(onFulfilled, onRejected){
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => {throw reason}
const promise2 = new TjfPromise((resolve, reject) => {
try{
const x = realOnFulfilled(this.value)
this.resolvePromise(promise2, x, resolve, reject) // 新增resolvePromise函数
}catch(error){
reject(error)
}
switch(this.status){
case FULFILLED:
realOnFulfilled(this.value)
break
case REJECTED:
realOnRejected(this.reason)
break
case PENDING:
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
this.REJECTED_CALLBACK_LIST.push(realOnRejected)
}
})
return promise2
}
}
开始实现resolvePromise函数
class TjfPromise{
......
resolvePromise(promise2, x, resolve, reject){
// 返回值就是promise2的时候,要直接返回错误
if( x === promise2) return new TypeError('The promise and the x refer to the same')
// x是Tjfpromise对象的时候, 要调用它的then方法
if( x instanceof TjfPromise){
x.then(resolve, reject)
} else {
resolve(x)
}
}
}
这里有一个问题,在这里promise2是还没有完成初始化的,因此会报错,那么我们需要把resolve的调用放在queueMicrotask微任务里面执行,同时把realOnRejected也一块处理一下
queueMicrotask里面执行resolvePromise
class TjfPromise{
......
then(onFulfilled, onRejected){
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => {throw reason}
const promise2 = new TjfPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
try{
queueMicrotask(() => { // 微任务里面调用
const x = realOnFulfilled(this.value)
this.resolvePromise(promise2, x, resolve, reject)
})
}catch(error){
reject(error)
}
}
const rejectedMicrotask = (() => {
try{
queueMicrotask(() => { // 微任务里面调用
const x = realOnRejected(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
})
}catch(error){
reject(error)
}
})
switch(this.status){
case FULFILLED:
fulfilledMicrotask()
break
case REJECTED:
rejectedMicrotask()
break
case PENDING:
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
}
})
return promise2
}
}
至此then函数的内容基本完结,下面按照promise A+规范把resolvePromise的内容完善一下
完善resolvePromise方法
class TjfPromise{
......
resolvePromise(promise2, x, resolve, reject){
if( x === promise2) return new TypeError('The promise and the x refer to the same')
if( x instanceof TjfPromise){
queueMicrotask(() => { // 这里又加了一层微任务,更加符合promise A+的调用
x.then( y => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if(typeof x === 'object' || this.isFunction(x)){
if(x === null) resolve(x)
let then = null
try{
then = x.then
} catch(error){
return reject(error)
}
if(this.isFunction(x.then)) {
let called = false
try{
then.call(x,(y) => {
if(called) return
called = true
this.resolvePromise(promise2, y, resolve, reject)
}, (error) => {
if(called) return
called = false
reject(error)
})
}catch(error){
if(called) return
reject(error)
}
} else {
resolve(x)
}
}else {
resolve(x)
}
}
}
到这里,resolvePromise方法也告一段落,测试一下
const promise = new TjfPromise((resolve, reject) => {
resolve('success')
})
function other () {
return new TjfPromise((resolve, reject) =>{
resolve('other')
})
}
promise.then(value => {
console.log(1)
console.log('resolve', value)
return other()
}).then(value => {
console.log(2)
console.log('resolve', value)
})
打印结果
1
resolve success
2
resolve other
没问题
静态方法的实现
promise内部有一些静态方法,就是只能通过prmise.race()调用,而不是实例调用,我们实现其中常用的几个
resolve方法
静态resolve方法就是返回了一个promise对象
class TjfPromise{
......
static resolve(value){
if(value instanceof TjfPromise){
return value
}
return new TjfPromise((resolve, reject) => {
resolve(value)
})
}
}
reject方法
静态reject方法返回一个带有reason的promise对象
class TjfPromise{
......
static reject(reason){
return new TjfPromise((resolve, reject) => {
reject(reason)
})
}
}
race方法
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
class TjfPromise{
static race(promiselist){
return new TjfPromise((resolve, reject) => {
if(!promiselist.length) return resolve()
promiselist.forEach( promiseitem => TjfPromise.resolve(promiseitem).then( value => resolve(value), reason => reject(reason)))
})
}
}
all 方法
promise.all(iterable)方法,返回一个promise实例,value的值为一个数组,如果有一个为rejected那么返回rejected
class TjfPromise{
......
static all(promiselist) {
return new TjfPromise((resolve, reject) => {
let valuelist = [];
let count = 0
if (!promiselist.length) return resolve();
promiselist.forEach((promiseitem, index) => {
TjfPromise.resolve(promiseitem).then(
(value) => {
valuelist[index] = value
count++
if (count === promiselist.length) resolve(valuelist)
},
(reason) => reject(reason)
);
});
});
}
}
测试一下
const promise1 = new TjfPromise((resolve, reject) => {
setTimeout(() => {
resolve(22)
},1000)
})
const promise2 = new TjfPromise((resolve, reject) => {
resolve(11)
})
TjfPromise.all([promise1, promise2]).then( value => console.log(value), reason => console.log(reason))
打印结果
[22, 11]
没有问题,那么以上就是prmise的全部实现了,附上全部完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class TjfPromise {
constructor(callback) {
this.status = PENDING;
this.value = null;
this._status = PENDING;
this.reason = null;
this.FULFILLED_CALLBACK_LIST = [];
this.REJECTED_CALLBACK_LIST = [];
try {
callback(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
get status() {
return this._status;
}
set status(newStatus) {
this._status = newStatus
if (newStatus === FULFILLED) {
this.FULFILLED_CALLBACK_LIST.forEach((callback) => callback(this.value));
}
if (newStatus === REJECTED) {
this.REJECTED_CALLBACK_LIST.forEach((callback) => callback(this.reason));
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value;
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (reason) => {throw reason};
const promise2 = new TjfPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
try {
queueMicrotask(() => {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
});
} catch (error) {
reject(error);
}
};
const rejectedMicrotask = () => {
try {
queueMicrotask(() => {
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
});
} catch (error) {
reject(error);
}
};
switch (this.status) {
case FULFILLED:
fulfilledMicrotask();
break;
case REJECTED:
rejectedMicrotask();
break;
case PENDING:
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
}
});
return promise2;
}
resolvePromise(promise2, x, resolve, reject) {
if (x === promise2)
return new TypeError("The promise and the x refer to the same");
if (x instanceof TjfPromise) {
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject);
}, reject);
});
} else if (typeof x === "object" || this.isFunction(x)) {
if (x === null) resolve(x);
let then = null;
try {
then = x.then;
} catch (error) {
return reject(error);
}
if (this.isFunction(x.then)) {
let called = false;
try {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
(error) => {
if (called) return;
called = false;
reject(error);
}
);
} catch (error) {
if (called) return;
reject(error);
}
} else {
resolve(x);
}
} else {
resolve(x);
}
}
static resolve(value) {
if (value instanceof TjfPromise) {
return value;
}
return new TjfPromise((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new TjfPromise((resolve, reject) => {
reject(reason);
});
}
static race(promiselist) {
return new TjfPromise((resolve, reject) => {
if (!promiselist.length) return resolve();
promiselist.forEach((promiseitem) =>
TjfPromise.resolve(promiseitem).then(
(value) => resolve(value),
(reason) => reject(reason)
)
);
});
}
static all(promiselist) {
return new TjfPromise((resolve, reject) => {
let valuelist = [];
let count = 0
if (!promiselist.length) return resolve();
promiselist.forEach((promiseitem, index) => {
TjfPromise.resolve(promiseitem).then(
(value) => {
valuelist[index] = value
count++
if (count === promiselist.length) resolve(valuelist)
},
(reason) => reject(reason)
);
});
});
}
isFunction(func) {
return typeof func === "function";
}
}
参考文章: