实现前有个规范必须了解: Promise/A+规范
Promise/A+规范
状态
Promise 对象存在以下三种状态:
const PENDING = 'PENDING';const RESOLVED = 'RESOLVED'; // 成功const REJECTED = 'REJECTED'; // 失败状态只能由PENDING变为RESOLVED或由PENDING变为REJECTED,且状态改变之后不会在发生变化,会一直保持这个状态。
Promise的值是指状态改变时传递给回调函数的值
Promise对象的then方法接受两个参数
promise.then(onFulfilled, onRejected)
参数可选
onFulfilled 和 onRejected 都是可选参数。
- 如果
onFulfilled或onRejected不是函数,其必须被忽略
onFulfilled 特性
如果 onFulfilled 是函数:
- 当
promise状态变为成功时必须被调用,其第一个参数为promise成功状态传入的值(resolve执行时传入的值) - 在
promise状态改变前其不可被调用 - 其调用次数不可超过一次
onRejected 特性
如果 onRejected 是函数:
- 当
promise状态变为失败时必须被调用,其第一个参数为promise失败状态传入的值(reject执行时传入的值) - 在
promise状态改变前其不可被调用 - 其调用次数不可超过一次
多次调用
then 方法可以被同一个 promise 对象调用多次
- 当
promise成功状态时,所有onFulfilled需按照其注册顺序依次回调 - 当
promise失败状态时,所有onRejected需按照其注册顺序依次回调
返回
then 方法必须返回一个新的 promise 对象
promise2 = promise1.then(onFulfilled, onRejected);
因此 promise 支持链式调用
promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);
这里涉及到 Promise 的执行规则,包括“值的传递”和“错误捕获”机制:
1、如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
- 若
x不为Promise,则使x直接作为新返回的Promise对象的值, 即新的onFulfilled或者onRejected函数的参数. - 若
x为Promise,这时后一个回调函数,就会等待该Promise对象(即x)的状态发生变化,才会被调用,并且新的Promise状态和x的状态相同。
下面的例子用于帮助理解:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
promise2 = promise1.then(res => {
// 返回一个普通值
return '这里返回一个普通值'
})
promise2.then(res => {
console.log(res) //1秒后打印出:这里返回一个普通值
})
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
promise2 = promise1.then(res => {
// 返回一个Promise对象
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('这里返回一个Promise')
}, 2000)
})
})
promise2.then(res => {
console.log(res) //3秒后打印出:这里返回一个Promise
})
2、如果 onFulfilled 或者onRejected 抛出一个异常 e ,则 promise2 必须变为失败(Rejected),并返回失败的值 e,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
promise2 = promise1.then(res => {
throw new Error('这里抛出一个异常e')
})
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) //1秒后打印出:这里抛出一个异常e
})
3、如果onFulfilled 不是函数且 promise1 状态为成功(Fulfilled), promise2 必须变为成功(Fulfilled)并返回 promise1 成功的值,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
console.log(res) // 1秒后打印出:success
}, err => {
console.log(err)
})
4、如果 onRejected 不是函数且 promise1 状态为失败(Rejected),promise2必须变为失败(Rejected) 并返回 promise1 失败的值,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('fail')
}, 1000)
})
promise2 = promise1.then(res => res, '这里的onRejected本来是一个函数,但现在不是')
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) // 1秒后打印出:fail
})
了解了规范就可以开始了
实现一个Promise
promise初始化
this.status = PENDING; // 默认是等待态
this.value = undefined; // 成功的原因
this.reason = undefined; // 失败的原因
// 专门存放成功的回调的函数
this.onResolvedCallbacks = [];
// 专门存放失败的回调函数的
this.onRejectedCallbacks = [];
promise里三个重要的方法
resolve(value){
if(this.state === PENDING){
this.state = RESOLVED
this.value = value
this.onFulfilledCallbacks.forEach((fn)=>fn())
}
}
reject(reason){
if(this.state === PENDING){
this.state = REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach((fn)=>fn())
}
}
then(onFulfilled, onRejected){
if(typeof onFulfilled !== 'function'){
// 空处理
onFulfilled = function(value){
return value
}
}
if(typeof onRejected !== 'function'){
// 空处理
onRejected = function(reason){
throw reason
}
}
if (this.status === RESOLVED) {
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onRejected(this.reason);
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
});
this.onRejectedCallbacks.push(() => {
onRejected(this.value)
});
}
}
resolve和reject主要任务就是把成功的值或者失败的原因保存起来,如果then里的onFulfilled或onRejected还未执行,则执行then里的方法
如果promise的then方法执行时,状态不是PENDING,则直接执行onFulfilled或者onRejected
onResolvedCallbacks和onRejectedCallbacks两个数组主要是异步的时候会用到,因为异步的时候then方法执行还是处于一个PENDING状态,所以要存起来,等promise成功或失败的时候再调用
到这里其实就实现了一个简单的promise,但是这样不能链式调用,要实现链式调用,then返回的必须还是一个promise,且这个then的值是下一个then的参数
promise解决方法
function resolvePromise (promise2,x,resolve,reject){
// 此方法 为了使所有的promise执行的流程是一样的
// 1) 不能引用同一个对象 可能会造成死循环
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise> --'))
}
let called;
if((typeof x ==='object' && x!=null) || typeof x === 'function'){
try{
let then = x.then; // {a:1} 因为then方法 可能使用的getter来定义的
if(typeof then === 'function'){ // 只能认为他是promise了
// call 改变this指向 并且让函数执行
then.call(x,y=>{ // 只取一次 当前promise解析出来的结果可能还是一个promise继续解析直到他是一个普通值为止
// 递归解析resolve的值
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},r=>{
if(called) return;
called = true;
reject(r);
})
}else{
// {a:1,then:1}
resolve(x)
}
}catch(e){ // 我取then出错了 在错误中又掉了该promise的成功
if(called) return
called = true;
reject(e); //取值失败 就走到error中
}
}else{
resolve(x)
}
}
全部代码
const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED'; // 成功
const REJECTED = 'REJECTED'; // 失败
function resolvePromise (promise2,x,resolve,reject){
// 此方法 为了兼容所有的promise,n个库中间 执行的流程是一样的
// 尽可能详细 不出错
// 1) 不能引用同一个对象 可能会造成死循环
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise> --'))
}
let called;
if((typeof x ==='object' && x!=null) || typeof x === 'function'){
try{
let then = x.then; // {a:1} 因为then方法 可能使用的getter来定义的
if(typeof then === 'function'){ // 只能认为他是promise了
// call 改变this指向 并且让函数执行
then.call(x,y=>{ // 只取一次 当前promise解析出来的结果可能还是一个promise继续解析直到他是一个普通值为止
// 递归解析resolve的值
if(called) return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},r=>{
if(called) return;
called = true;
reject(r);
})
}else{
// {a:1,then:1}
resolve(x)
}
}catch(e){ // 我取then出错了 在错误中又掉了该promise的成功
if(called) return
called = true;
reject(e); //取值失败 就走到error中
}
}else{
resolve(x)
}
}
class Promise {
constructor(executor) { // 宏变量
this.status = PENDING; // 默认是等待态
this.value = undefined; // 成功的原因
this.reason = undefined; // 失败的原因
// 专门存放成功的回调的函数
this.onResolvedCallbacks = [];
// 专门存放失败的回调函数的
this.onRejectedCallbacks = [];
// 保证只有状态是等待态的时候 才能更改状态
let resolve = (value) => {
// 增加
if(value instanceof Promise){
value.then(resolve,reject);// 递归解析直到是普通值位置
return;
}
if (this.status === PENDING) {
this.value = value;
this.status = RESOLVED;
// 需要让成功的方法依次执行
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn());
}
} // 执行executor 传入成功和失败
try {
executor(resolve, reject); // 立即执行
} catch (e) {
reject(e); // 如果内部出错直接将err手动的调用reject方法向下传递
}
}
catch(errCallback){ // catch就是没有成功的then方法
return this.then(null,errCallback)
}
then(onfulfilled, onrejected) {
onfulfilled = typeof onfulfilled == 'function'?onfulfilled:v=>v;
onrejected = typeof onrejected == 'function'?onrejected:err=>{throw err}
// 为了实现链式调用 就创建一个新的promise
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onfulfilled(this.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) { // 一旦执行then方法报错 就走到外层then的错误处理中,调用promise2的reject方法
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onrejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === PENDING) {
// 这时候 executor是肯定有异步逻辑
this.onResolvedCallbacks.push(() => {
// TODO... 切片编程
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; // 返回这个promise
}
}
Promise.defer = Promise.deferred = function () { // 稍后继续说 catch
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
module.exports = Promise;
// npm install -g promises-aplus-tests
总结
promise是一个立即执行方法,接收一个方法,这个方法接收两个参数,第一个是resolve,第二个是reject。promise对象里有then方法和catch方法,catch其实就是失败的的then方法。promise内部有三种状态,
const PENDING = 'PENDING';
const RESOLVED = 'RESOLVED'; // 成功
const REJECTED = 'REJECTED'; // 失败
状态只能从PENDING到成功或失败,且改变了就不能再变回去了。状态只能从resolve方法或者reject方法改变。 then方法接收两个参数,第一个是 onfulfilled,第二个是onrejected,onfulfilled方法里接收promise成功时的值,onrejected方法里接收promise失败的原因。 当执行then方法时,如果此时promise的状态是成功或者失败,则直接执行onfulfilled或onrejected方法。如果此时promise的状态是PENDING,则分别把onfulfilled和onrejected存到该promise中的专门存放成功和失败的回调函数的数组中,等待promise触发了resolve或者reject方法时再遍历执行之前存起来的onfulfilled和onrejected。
promise里最难的应该时链式调用的解决方法,由于能链式调用,所以then方法返回的一定还是一个promise对象。 解决链式调用需要一个promise解决方法我们把它叫做resolvePromise,这个方法接收4个参数,(promise2,x,resolve,reject),promise2是then方法返回出来的promise,x是then方法接收的onfulfilled方法或者onrejected的返回值,resolve,reject是promise2的resolve,reject。 在resolvePromise里首先判断x !==promise2,因为这样会导致死循环。然后判断x的类型如果是promise则递归resolvePromise,是普通值则直接resolve(x)。
参考资料