# 手写promise
Promise 其实就是一个构造函数,可以使用这个构造函数创建一个 Promise 实例。
该构造函数很简单,它只有一个参数,按照 Promise/A+ 规范的命名,把 Promise 构造函数的参数叫做 executor,executor 类型为函数。这个函数又「自动」具有 resolve、reject 两个方法作为参数。
- 创建Promise函数
function Promise(executor) {
}
避免微信小程序请求的回调地狱,可以自己封装一个wxRequest对象:
wxRequest('./userInfo')
.then(
data => wxRequest(`./${data.id}/friendList`),
error => {
console.log(error)
}
)
.then(
data => {
console.log(data)
},
error => {
console.log(error)
}
)
Promise 构造函数返回一个 promise 对象实例,这个返回的 promise 对象具有一个 then 方法。then 方法中,调用者可以定义两个参数,分别是
onfulfilled和onrejected,它们都是函数类型。其中 onfulfilled 通过参数,可以获取 promise 对象 resolved 的值,onrejected 获得 promise 对象 rejected 的值。通过这个值,我们来处理异步完成后的逻辑。
- 完善promise
function Promise(executor) {
}
Promise.prototype.then = function(onfulfilled, onrejected) {
}
看promise例子:
let promise1 = new Promise((resolve, reject) => {
resolve('data')
})
promise1.then(data => {
console.log(data)
})
let promise2 = new Promise((resolve, reject) => {
reject('error')
})
promise2.then(data => {
console.log(data)
}, error => {
console.log(error)
})
在使用 new 关键字调用 Promise 构造函数时,在合适的时机(往往是异步结束时),调用 executor 的参数 resolve 方法,并将 resolved 的值作为 resolve 函数参数执行,这个值便可以后续在 then 方法第一个函数参数(onfulfilled)中拿到;同理,在出现错误时,调用 executor 的参数 reject 方法,并将错误信息作为 reject 函数参数执行,这个错误信息可以在后续的 then 方法第二个函数参数(onrejected)中拿到。
因此,在实现 Promise 时,应该有两个值,分别储存 resolved 的值,以及 rejected 的值(当然,因为 Promise 状态的唯一性,不可能同时出现 resolved 的值和 rejected 的值,因此也可以用一个变量来存储);同时也需要存在一个状态,这个状态就是 promise 实例的状态(pending,fulfilled,rejected);同时还要提供 resolve 方法以及 reject 方法,这两个方法需要作为 executor 的参数提供给开发者使用:
- 添加resolve reject方法,同时添加存取成功失败值的两个变量(如果创建的函数是用箭头函数,那么就不需要self)
function Promise(executor) {
const self = this
this.status = 'pending'
this.value = null
this.reason = null
function resolve(value) {
self.value = value
}
function reject(reason) {
self.reason = reason
}
executor(resolve, reject)
}
Promise.prototype.then = function(onfulfilled = Function.prototype, onrejected = Function.prototype) {
onfulfilled(this.value)
onrejected(this.reason)
}
当promise的状态发生变化,是不可逆的!所以还是要处理。
- 不可以同时执行多个resolve/reject
//promiseA+
function Promise(executor){
this.value = null
this.reason = null
this.status = 'pending'
const resolve = data=>{
if(this.status === 'pending'){
this.value =data
this.status ='fulfilled'
}
}
const reject = reason=>{
if(this.status === 'pending'){
this.reason =reason
this.status ='rejected'
}
}
executor(resolve,reject)
}
Promise.prototype.then =function(onfulfilled,onrejected){
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
if(this.status === 'fulfilled'){
onfulfilled(this.value)
}
if(this.status === 'rejected'){
onrejected(this.reason)
}
}
- 异步操作处理:应该是开发者调用 resolve 的时刻,那么先在状态(status)为 pending 时,把开发者传进来的 onfulfilled 方法存起来,在 resolve 方法中再去执行即可。
//promiseA+
function Promise(executor){
this.value = null
this.reason = null
this.status = 'pending'
this.onFulfilledFunc = Function.prototype
this.onRejectedFunc = Function.prototype
const resolve = data=>{
if(this.status === 'pending'){
this.value =data
this.status ='fulfilled'
console.log(this.status)
this.onFulfilledFunc(this.value)
}
}
const reject = reason=>{
if(this.status === 'pending'){
this.reason =reason
this.status ='rejected'
console.log(this.status)
this.onRejectedFunc(this.reason)
}
}
executor(resolve,reject)
}
Promise.prototype.then =function(onfulfilled,onrejected){
console.log(onfulfilled)
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
if(this.status === 'fulfilled'){
onfulfilled(this.value)
}
if(this.status === 'rejected'){
onrejected(this.reason)
}
if(this.status === 'pending'){
console.log(this.status)
this.onFulfilledFunc = onfulfilled
this.onRejectedFunc = onrejected
}
}
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data')
},2000)
})
promise.then(data => {
console.log(data)
})
- 同步代码优先异步/回调执行,同时在 resolve 方法中,加入了对 value 值是一个 Promise 实例的判断
//promiseA+
function Promise(executor){
this.value = null
this.reason = null
this.status = 'pending'
this.onFulfilledFunc = Function.prototype
this.onRejectedFunc = Function.prototype
const resolve = data=>{
if(data instanceof Promise){
return data.then(resolve,reject)
}
setTimeout(()=>{
if(this.status === 'pending'){
this.value =data
this.status ='fulfilled'
this.onFulfilledFunc(this.value)
}
})
}
const reject = reason=>{
setTimeout(()=>{
if(this.status === 'pending'){
this.reason =reason
this.status ='rejected'
this.onRejectedFunc(this.reason)
}
})
}
executor(resolve,reject)
}
Promise.prototype.then =function(onfulfilled,onrejected){
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
if(this.status === 'fulfilled'){
onfulfilled(this.value)
}
if(this.status === 'rejected'){
onrejected(this.reason)
}
if(this.status === 'pending'){
this.onFulfilledFunc = onfulfilled
this.onRejectedFunc = onrejected
}
}
- 此时的项目还存在问题,两个promise调用只会去触发第二个,而第一个则被覆盖了
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data')
}, 2000)
})
promise.then(data => {
console.log(`1: ${data}`)
})
promise.then(data => {
console.log(`2: ${data}`)
})
//2: data
- 解决覆盖问题:只需要将所有 then 方法中的 onFulfilledFunc 储存为一个数组 onFulfilledArray,在 resolve 时,依次执行即可。对于 onRejectedFunc 同理;同时对executor函数做个trycatch处理。
//promiseA+
function Promise(executor){
this.value = null
this.reason = null
this.status = 'pending'
this.onFulfilledArray = []
this.onRejectedArray =[]
const resolve = data=>{
if(data instanceof Promise){
return data.then(resolve,reject)
}
setTimeout(()=>{
if(this.status === 'pending'){
this.value =data
this.status ='fulfilled'
// this.onFulfilledFunc(this.value)
this.onFulfilledArray.forEach(func=>{
func(this.value)
})
}
})
}
const reject = reason=>{
setTimeout(()=>{
if(this.status === 'pending'){
this.reason =reason
this.status ='rejected'
// this.onRejectedFunc(this.reason)
this.onRejectedArray.forEach(func=>{
func(this.reason)
})
}
})
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
Promise.prototype.then =function(onfulfilled,onrejected){
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
if(this.status === 'fulfilled'){
cosnole.log(11)
onfulfilled(this.value)
}
if(this.status === 'rejected'){
onrejected(this.reason)
}
if(this.status === 'pending'){
// this.onFulfilledFunc = onfulfilled
this.onFulfilledArray.push(onfulfilled)
// this.onRejectedFunc = onrejected
this.onRejectedArray.push(onrejected)
}
}
let promise = new Promise((resolve, reject) => {
// setTimeout(() => {
resolve('data')
// }, 2000)
})
promise.then(data => {
console.log(`1: ${data}`)
})
promise.then(data => {
console.log(`2: ${data}`)
})
promise.then(data => {
console.log(`2: ${data}`)
})
promise.then(data => {
console.log(`3: ${data}`)
})
一个 Promise 实例的 then 方法体 onfulfilled 函数和 onrejected 函数中,是支持再次返回一个 Promise 实例的,也支持返回一个非 Promise 实例的普通值;并且返回的这个 Promise 实例或者这个非 Promise 实例的普通值将会传给下一个 then 方法 onfulfilled 函数或者 onrejected 函数中,这样就支持链式调用了。
- promise的链式调用实现:
function Promise(executor){
this.status = 'pending'
this.value = null
this.reason = null
// this.onfulfilledFunc = Function.prototype
// this.onrejectedFunc = Function.prototype
// promise 实例状态变更之前,添加多个 then 方法,所有的状态是一致的,所以可以用数组依次添加
this.onfulfilledArray = []
this.onrejectedArray = []
const resolve = value => {
// 这里的作用:如果value是Promise,则需要继续执行下一步
if(value instanceof Promise){
return value.then(resolve,reject)
}
setTimeout(()=>{
if(this.status === 'pending'){
this.value = value
this.status = 'fulfilled'
// this.onfulfilledFunc(this.value)
console.log(this.onfulfilledArray)
this.onfulfilledArray.forEach(func=>{
func(this.value)
})
}
})
}
const reject = reason =>{
setTimeout(()=>{
if(this.status === 'pending'){
this.reason = reason
this.status = 'rejected'
// this.onrejectedFunc(this.reason)
this.onrejectedArray.forEach(func=>{
func(this.reason)
})
}
})
}
try{
executor(resolve,reject)
}catch(e){
reject(e)
//TODO handle the exception
}
}
Promise.prototype.then = function(onfulfilled,onrejected){
onfulfilled = typeof onfulfilled === "function"?onfulfilled:data=>data
onrejected = typeof onrejected === 'function'?onfulfilled:error=>{ throw error }
let promise2
if(this.status === 'fulfilled'){
console.log(this.status,'status')
// onfulfilled(this.value)
// 实现链式调用功能,需要返回一个promise
return promise2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
try{
let result = onfulfilled(this.value)
resolve(result)
}catch(e){
reject(e)
//TODO handle the exception
}
})
})
}
if(this.status === 'rejected'){
// onrejected(this.reason)
return promise2 = new Promise((resolve,reject)=>{
try{
let result = onrejected(this.reason)
resolve(result)
}catch(e){
reject(e)
//TODO handle the exception
}
})
}
if(this.status === 'pending'){
// console.log(this.status,'status')
// this.onfulfilledFunc = onfulfilled
// this.onrejectedFunc = onrejected
// this.onfulfilledArray.push(onfulfilled)
// this.onrejectedArray.push(onrejected)
promise2 = new Promise((resolve,reject)=>{
this.onfulfilledArray.push(() => {
try {
let result = onfulfilled(this.value)
// 链式调用需要
resolve(result)
}
catch(e) {
reject(e)
}
})
this.onrejectedArray.push(() => {
try {
let result = onrejected(this.reason)
resolve(result)
}
catch(e) {
reject(e)
}
})
})
console.log(promise2)
return promise2
}
}
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data')
})
})
promise.then(data => {
console.log(`1: ${data}`)
}).then(res=>{
console.log(res)
return 10000088
}).then(res=>{
console.log(res)
}).then(res=>{
console.log(res)
})
promise.then(data => {
console.log(`2: ${data}`)
})
// 1. 状态只能变一次
// 2. 如果 resolve 异步执行,then 已经调用过,还在 pending 状态时,所以需要想办法在 resolve 执行时接住 onfulfilled/onrejected
// 3. Promise 是异步执行的,需要控制 resolve 和 reject 的执行时间
// 4.为了能够支持 then 方法的链式调用,那么每一个 then 方法的 onfulfilled 函数和 onrejected 函数都应该返回一个 Promise 实例。
# 完整范例1
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);
};
});
}
# 完整范例2
class HD {
static PENDING = 'pending'; // 准备
static FUlFILLED = 'fulfilled'; // 解决
static REJECTED = 'rejected'; // 拒绝
constructor(executor) {
this.status = HD.PENDING;
this.value = null;
this.callbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
// 异步特性
if (this.status == HD.PENDING) {
this.status = HD.FUlFILLED;
this.value = value;
// 让与resolve同块的方法先执行
setTimeout(() => {
// 处理准备时期 then 放入的回调
this.callbacks.forEach(callback => {
callback['onFulfilled'](value);
})
})
}
}
reject(reason) {
// 异步特性
if (this.status == HD.PENDING) {
this.status = HD.REJECTED;
this.value = reason;
// 让与resolve同块的方法先执行
setTimeout(() => {
// 处理准备时期 then 放入的回调
this.callbacks.forEach(callback => {
callback['onRejected'](reason);
})
})
}
}
then(onFulfilled, onRejected) {
// 没传resolve方法
if (typeof onFulfilled != 'function') {
// then值穿透
onFulfilled = () => this.value;
}
// 没传reject方法
if (typeof onRejected != 'function') {
// 没有catch异常
onRejected = function () {
throw new Error("Unexpected end of input")
}
}
let promise = new HD((resolve, reject) => {
// 准备
if (this.status == HD.PENDING) {
this.callbacks.push({
onFulfilled: value => {
// 冗余代码的优化
HD.parse(promise, onFulfilled(value), resolve, reject)
},
onRejected: reason => {
// 冗余代码的优化
HD.parse(promise, onRejected(reason), resolve, reject)
}
});
}
// 处理
else if (this.status == HD.FUlFILLED) {
// 等待this.next赋值
setTimeout(() => {
// 冗余代码的优化
HD.parse(promise, onFulfilled(this.value), resolve, reject)
})
}
// 拒绝
else if (this.status == HD.REJECTED) {
// 等待this.next赋值
setTimeout(() => {
// 冗余代码的优化
HD.parse(promise, onRejected(this.value), resolve, reject)
})
}
});
return promise;
}
static parse(promise, result, resolve, reject) {
// 禁止同一个then中循环返回 promise
console.log(promise,result)
if (promise == result) {
throw new TypeError('Chaining cycle detected')
}
try {
// 设置结果值
if (result instanceof HD) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
static resolve(value) {
return new HD((resolve, reject) => {
HD.parse(null, value, resolve, reject);
})
}
static reject(value) {
return new HD((resolve, reject) => {
reject(value)
})
}
/**
* 全成功,返回全部返回值
* 有失败,返回第一个失败信息
* @param {HD} promises
*/
static all(promises) {
return new HD((resolve, reject) => {
const values = [];
promises.forEach((promise) => {
promise.then(
value => {
values.push(value)
if (values.length == promises.length) {
resolve(values);
}
},
reason => {
reject(reason)
}
)
})
})
}
/**
* race(竞赛)
* 返回第一个返回值
* @param {HD} promises
*/
static race(promises) {
return new HD((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => {
return resolve(value);
},
reason => {
return reject(reason);
}
)
})
})
}
}
← 手写vue 手写instanceof →