# 手写一个Promise
# Promise
# 三种状态
一个Promise对象有三种状态:
pending(进行中)
fulfilled(已成功)
rejected(已失败)
状态只有两种转变可能,从pending到fulfilled,或者从pending到rejected。
# 基本用法
var promise = new Promise((resolve,reject)=>{
let flag = true;
if (flag) {
// return resolve('not promise') 在前面增加return,resolve后面的代码不再执行
resolve('not promise') // resolve不会阻止后面的代码执行,then的执行属于微任务部分
console.log('before not promise') // 所以'before not promise'先打印
} else {
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('test')
},3000)
})
resolve(p) // 三秒后输出'test'
/**
* 当resolve方法传入一个新的Promise对象p,p的状态会传给原Promise对象promise:
* 如果p的状态是pending,那么promise的回调函数就会等待p的状态改变;
* 如果p的状态已经是resolved或者rejected,那么promise的回调函数将会立刻执行。
*/
}
}).then(res=>{
console.log(res)
}).then(res=>{
/**
* Promise.prototype.then
* then方法的作用是为 Promise 实例添加状态改变时的回调函数
* 第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,均为可选
* then方法返回的是一个新的Promise实例,因此可以采用链式写法
*/
}).catch(err=>{
console.log(err)
/**
* Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数
*/
})
# 其他方法
(下方引用参见ECMAScript 6 入门 (opens new window))
# Promise.prototype.finally()
finally方法不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。
这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
# Promise.all()
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。
Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。
另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected。
# Promise.race()
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。
Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
# Promise.allSettled() ES2020
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。
该方法返回的新的 Promise 实例,一旦结束,状态总是fulfilled,不会变成rejected。
状态变成fulfilled后,Promise 的监听函数接收到的参数是一个results数组,每个成员对应一个传入Promise.allSettled()的 Promise 实例。
# Promise.any() ES2021
接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是不会因为某个 Promise 变成rejected状态而结束。
# Promise.resolve()
将现有对象转为 Promise 对象。
(1)参数是一个 Promise 实例:如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象:Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。
(3)参数不是具有then()方法的对象,或根本就不是对象:Promise.resolve()方法返回一个新的 Promise 对象,其状态从一生成就是resolved,所以回调函数会立即执行,Promise.resolve()的入参会传给回调函数。
(4)不带有任何参数:直接返回一个resolved状态的 Promise 对象。
# Promise.reject()
Promise.reject()方法也会返回一个新的 Promise 实例,该实例的状态为rejected
# 模拟实现
# 基本功能实现
//定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
constructor (handle) {
this._status = PENDING;
this._value = null; // fultilled状态的值,即调用resolve的入参
this._error = null; // rejected状态的值,即调用reject的入参
this.onFulfilledCallbacks = []; // fultilled状态回调函数栈
this.onRejectedCallbacks = []; // rejected状态回调函数栈
try {
handle(this._resolve.bind(this), this._reject.bind(this))
} catch (err) {
this._reject(err)
}
}
_resolve (value) {
var self = this;
//当resolve方法传入一个新的Promise对象,则等待其完成或失败
if(value instanceof MyPromise) {
return value.then(self._resolve.bind(self), self._reject.bind(self));
}
// 判断状态
if (this._status !== PENDING) return
// 放在setTimeout中执行,为了在new Promise时传入的同步任务在then方法注册回调后,调用前执行
setTimeout(()=>{
self._status = FULFILLED;
self._value = value;
self.onFulfilledCallbacks.forEach(cb => cb(self._value));
},0);
}
_reject (error) {
var self = this;
// 判断状态
if (this._status !== PENDING) return
// 放在setTimeout中执行,为了在new Promise时传入的同步任务在then方法注册回调后,调用前执行
setTimeout(()=>{
self._status = REJECTED;
self._error = error;
self.onRejectedCallbacks.forEach(cb => cb(self._error));
},0);
}
then (onFulfilled, onRejected) {
var self = this;
let bridgePromise; // then返回的promise对象
// 处理回调,使之必然为一个函数
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
onRejected = typeof onRejected === "function" ? onRejected : error => { throw error };
return bridgePromise = new MyPromise((resolve, reject) => {
// 封装回调
let getCallback = function(flag) {
return function(val) {
try {
let res = flag ? onFulfilled(val) : onRejected(val);
// 如果回调函数返回一个Promise对象,则等待其完成或失败
res instanceof MyPromise
? res.then(resolve, reject)
: resolve(res)
} catch (err) {
reject(err)
}
}
}
switch (self._status) {
case PENDING:
self.onFulfilledCallbacks.push(getCallback(true))
self.onRejectedCallbacks.push(getCallback(false))
break
case FULFILLED:
getCallback(true)(self._value)
break
case REJECTED:
getCallback(false)(self._error)
break
}
})
}
catch (onRejected) {
return this.then(null, onRejected)
}
}
# 基本功能测试
var promise = new MyPromise((resolve,reject)=>{
var flag = 2;
switch (flag) {
case 1:
resolve('not promise')
console.log('before not promise')
break
case 2:
let p = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('test')
},3000)
})
resolve(p)
break
case 3:
reject("some error")
}
}).then(res=>{
console.log(res)
}).then(res=>{
console.log(123)
console.log(res)
}).catch(err=>{
console.log(err)
})
flag = 1
flag = 2
flag = 3
# 其他方法实现
(下方实现来自Promise实现原理 (opens new window))
class MyPromise {
static resolve (value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve, reject) => resolve(value));
}
static reject (value) {
return new MyPromise((resolve, reject) => reject(value));
}
static all (list) {
return new MyPromise((resolve, reject) => {
let values = []
let count = 0
for (let [i, p] of list.entries()) {
this.resolve(p).then(res => {
values[i] = res;
count++;
if (count === list.length) resolve(values);
}, err => {
reject(err);
})
}
})
}
static race (list) {
return new MyPromise((resolve, reject) => {
for (let p of list) {
this.resolve(p).then(res => {
resolve(res);
}, err => {
reject(err);
})
}
})
}
finally (cb) {
return this.then(
value => MyPromise.resolve(cb()).then(() => value),
reason => MyPromise.resolve(cb()).then(() => { throw reason })
);
}
}
# 其他方法测试
var p1 = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(1)
},1000)
})
var p2 = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(2)
},2000)
})
var p3 = new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve(3)
},3000)
})
MyPromise.race([p1,p2,p3]).then(res=>{
console.log(res)
})
MyPromise.all([p1,p2,p3]).then(res=>{
console.log(res)
})
console.log(MyPromise.resolve('string').then(res=>{console.log(res)}))
console.log(MyPromise.reject('error'))
p3.finally(()=>{
console.log('this is a fanally callback')
})
# 参考
Promise 对象 - 阮一峰 (opens new window)