废了1-2天功夫编写了一套能实现异步Promise的构造函数,实现以下功能:
(1)通过newPromise((res,rej)=>{})构造一个Promise功能的方法
(2)通过then获取onFulfilled或者onRejected状态返回的值
(3)通过catch捕获之前rejected的错误
/*promise状态,PENDING阻塞、FULFILLED完成、REJECTED失败*/
const PENDING = 0,
FULFILLED = 1,
REJECTED = 2;
/*then中需要返回一个新的promise,promise初始化用的resolver*/
function noop() {
};
/*resolver必须为一个方法,不是给出typeError提示*/
function needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor')
}
/*Promise构造函数生成,不是给出typeError提示*/
function needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")
}
class newPromise {
constructor(resolver) {
/*当前Promise状态*/
this.PromiseStatus = PENDING
/*final执行时需要的标记,防止乱序执行*/
this._deferredState = 0 //1在进行final 否则不在
/*存放的后续then执行的({onFulfilled,onRejected})方法*/
this._deferreds = []
/*保存当前值,可以是resolve或者reject返回的值*/
this.PromiseValue = null
/*resolver是否是方法,不是提示报错信息*/
typeof resolver !== 'function' && needsResolver();
this instanceof newPromise ? init_(this, resolver) : needsNew();
}
}
newPromise.prototype.then = then_
newPromise.prototype.catch = catch_
function init_(promise, resolver) {
try {
resolver((val) => {
resolve_(promise, val)
}, (err) => {
reject_(promise, err)
})
} catch (e) {
catch_(e)
}
}
/*与then相似,只是没有onFulfilled参数*/
function catch_(onRejected) {
var promise = new newPromise(noop);
let handler = new Handler(this, null, onRejected, promise)
pushTo_(this, handler)
return promise;
}
/*reject,resolve之后会调用*/
function final_(promise) {
if (promise._deferreds.length > 0) {//将结果返回
if (promise._deferredState === 1) return
promise._deferredState = 1
let defer = promise._deferreds[0]
handle_(promise, defer);
}
}
function pushTo_(promise, deferred) {
promise._deferreds.push(deferred)
}
function handle_(self, defer) {//{defer 是一个对象,有三个参数:onFulfilled,onRejected,promise
var cb = self.PromiseStatus === FULFILLED ? defer.onFulfilled : defer.onRejected;
if (cb === null) {
/*状态不变,再次调用then才将PromiseValue输出*/
self._deferreds.pop()
if (self.PromiseStatus === FULFILLED) {
resolve_(self, self.PromiseValue)
} else {
reject_(self, self.PromiseValue)
}
self._deferredState = 0
}
else if (self.PromiseStatus === PENDING) {
// if (self._deferredState === 0) {
// self._deferredState = 1;
// }
}
else {
self._deferreds.pop()
self._deferredState = 0
let promise = self.promise
let callback = cb(self.PromiseValue)
if (callback) {
callback.then(res => {
// console.log('---', callback)
// if (callback.PromiseStatus === REJECTED)
// reject_(promise, callback.PromiseValue)
// else
/*将callback返回值,在之前then生成的promise上发出,则promise.then可以捕获到,这样then就可以变成链式的了*/
resolve_(promise, callback.PromiseValue)
}, rej => {
reject_(promise, callback.PromiseValue)
})
}
}
}
//返回一个新的promise
function then_(onFulfilled, onRejected) {
var promise = new newPromise(noop);
let handler = new Handler(this, onFulfilled, onRejected, promise)
pushTo_(this, handler)
return promise;
}
function resolve_(promise, val) {
promise.PromiseStatus = FULFILLED
promise.PromiseValue = val
final_(promise)
}
function reject_(promise, err) {
promise.PromiseStatus = REJECTED
promise.PromiseValue = err
final_(promise)
}
function Handler(promise, onFulfilled, onRejected, promise_) {
promise.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
promise.onRejected = typeof onRejected === 'function' ? onRejected : null;
promise.promise = promise_;
return promise
}
复制代码
测试代码:
let newp = new newPromise((resolve, reject) => {
setTimeout(() => {
reject('1')
})
}).then(resolve => {
console.log('resolve', resolve)
}, reject => {
console.log('reject:', reject)
return new newPromise((resolve) => {
setTimeout(() => {
resolve('ok')
}, 100)
})
}).then(res => {
console.log('---res---', res)
return new newPromise((resolve, reject) => {
setTimeout(() => {
reject('ok')
}, 100)
})
}).then(res => {
console.log('---res2---', res)
}, rej => {
console.log('---rej2---', rej)
return new newPromise((resolve, reject) => {
setTimeout(() => {
reject('err')
}, 100)
})
}).catch(err => {
console.log(err)
})
复制代码
测试结果: