前言
这里引用阮老师ES6入门里对Primose对象的定义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。 它有两个特点:
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
实现Promise
基于概念,接下来手写一个Promise
class PromiseA {
constructor(exectuor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
}
}
const reject = (reason) => {
if (this.status === 'pending') {
this.reason = reason;
this.status === 'rejected';
}
}
exectuor(resolve, reject);
}
then(onResolved, onRejected) {
const resolved = typeof onResolved === 'function' ? onResolved : v => v;
const rejected = typeof onRejected === 'function' ? onRejected : r => r;
if (this.status === 'fulfilled') {
resolved(this.value);
}
if (this.status === 'rejected') {
rejected(this.reason);
}
}
}
代码很简单,重点是在resolve,reject两个方法中改变当前Promise的状态。 测试一下,一切顺利
const promise = new PromiseA((resolve) => {
resolve('promise success');
}).then((data) => {
console.log(data); // promise success
})
如果在Promise的回调函数中异步处理resolve,最终并没有得到想要的结果,原因在于此时调用then,status还处于pending状态,根本就不会执行then方法中的resolved或者rejected。
new PromiseA((resolve, reject) => {
setTimeout(() => {
resolve('promise success')
});
}).then((data) => {
// 注意:根本不会执行到这里
console.log(data);
})
这样需要增加对异步调用的处理,基本思路是先将resolved或者rejected方法加到数组中,等到resolve()执行时,遍历数组中的resolved/rejected,其实本质就是观察者模式。
class PromiseA {
constructor(exectuor) {
...... // 省略部分
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
// 循环遍历执行resolved()
this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = (reason) => {
if (this.status === 'pending') {
this.reason = reason;
this.status === 'rejected';
this.onRejectedCallbacks.forEach(fn => fn());
}
}
exectuor(resolve, reject);
}
then(onResolved, onRejected) {
...... // 省略部分
// 新增部分
if(this.status === 'pending') {
this.onResolvedCallbacks.push(() => {
resolved(this.value);
});
this.onRejectedCallbacks.push(() => {
rejected(this.reason);
})
}
}
}
测试一下,一切顺利。
const promise = new PromiseA((resolve) => {
setTimeout(() => {
resolve('promise success');
});
}).then((data) => {
console.log(data); // promise success
})
then的链式调用
采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。 要实现then的链式调用,必须对then的返回值进行处理,增加一个方法用于处理then方法的返回值。
// 处理then的链式调用
function resolveThen(promisable, promise, resolve, reject) {
if (promisable === promise) {
throw ('promise不能为同一个引用对象');
}
try {
// 判断promise是否为对象,如果是做进一步处理
// 如果不是,说明promise是基本值,直接用resolve处理
if (promise && typeof promise === 'object') {
const then = promise.then;
// 判断promise是否有then方法,如果有做进一步处理
// 如果没有,说明promise是个普通对象,直接用resolve处理
if (then && typeof then === 'function') {
// 递归处理是promise的情况
then.call(promise, y => {
resolveThen(promise2, y, resolve, reject);
}, r => {
reject(r);
})
} else {
resolve(promise);
}
} else {
resolve(promise)
}
} catch (error) {
reject(error);
}
}
then方法返回一个Promise对象
export class PromiseA {
...... // 省略
then(onResolved, onRejected) {
const resolved = typeof onResolved === 'function' ? onResolved : v => v;
const rejected = typeof onRejected === 'function' ? onRejected : r => r;
const promise = new PromiseA((resolve, reject) => {
if (this.status === 'fulfilled') {
const value = resolved(this.value);
resolveThen(promise, value, resolve, reject);
}
if (this.status === 'rejected') {
const reason = rejected(this.reason);
resolveThen(promise, reason, resolve, reject);
}
if (this.status === 'pending') {
this.onResolvedCallbacks.push(() => {
const value = resolved(this.value);
resolveThen(promise, value, resolve, reject);
});
this.onRejectedCallbacks.push(() => {
const reason = rejected(this.reason);
resolveThen(promise, reason, resolve, reject);
})
}
});
return promise;
}
}
这样就实现了then的链式调用,测试一下,一切顺利
const promise = new PromiseA((resolve) => {
setTimeout(() => {
resolve('promise success');
});
}).then((data) => {
console.log(data); // promise success
return 'promise then success';
}).then((data) => {
console.log(data); // promise then success
})
后续会更新Promise.resolve,Promise.all等静态方法的实现。