我們手寫一個(gè)Promise/A 規(guī)范,然后安裝測(cè)試腳本,以求通過(guò)這個(gè)規(guī)范。
//Promise/A 源代碼
// new Promise時(shí),需要傳遞一個(gè)executor執(zhí)行器,執(zhí)行器立即執(zhí)行
// executor接受兩個(gè)參數(shù),分別是resolve和reject
// promise只能從pending到rejected,或者從pending到fulfilled
// promise的狀態(tài)一旦確認(rèn),就不會(huì)再改變
// promise有then方法,then接受兩個(gè)參數(shù),分別是promise成功的回調(diào)onFulfilled
// 和promise失敗的回調(diào) onRejected
// 如果調(diào)用then時(shí),promise已經(jīng)成功,則執(zhí)行onFulfilled,并將promise值作為參數(shù)傳遞進(jìn)去
// 如果promise已經(jīng)失敗,那么執(zhí)行onRejected并把promise失敗的原因作為參數(shù)傳遞進(jìn)去
// 如果promise狀態(tài)是pending,需要將onFulfilled和onRejected函數(shù)存放起來(lái),等待狀態(tài)確定后,再一次將對(duì)應(yīng)的函數(shù)執(zhí)行(發(fā)布)
// then的參數(shù)onFulfilled和onRejected可以缺省
// promise可以then多次,promise的then方法返回一個(gè)promise
// 如果then返回的是一個(gè)結(jié)果,那么就把這個(gè)結(jié)果作為參數(shù),傳遞給下一個(gè)then的成功的回調(diào)onFulfilled
// 如果then中拋出了異常,那么就會(huì)把這個(gè)異常作為參數(shù),傳遞給下一個(gè)失敗的回調(diào) onRejected
// 如果then返回的是一個(gè)promise,那么需要等這個(gè)promise,那么會(huì)等這個(gè)promise執(zhí)行完,promise如果成功
// 就走下一個(gè)then的成功,如果失敗,就走下一個(gè)then的失敗
//pending狀態(tài),可以認(rèn)為是一種中間狀態(tài)
const PENDING = 'pending';
// fullfilled完成狀態(tài),可以認(rèn)為是成功回調(diào)了的狀態(tài)
const FULFILLED = 'fullfilled';
// reject即為拒絕狀態(tài),即失敗的狀態(tài)
const REJECTED = 'reject';
// executor是一個(gè)執(zhí)行器
function Promise(executor){
let self = this;
self.status = PENDING;
self.onFulfilled = [];//成功的回調(diào)
self.onRejected = [];//失敗的回調(diào)
// PromiseA 2.1
function resolve(value){
if(self.status === PENDING){
self.status = FULFILLED;
self.value = value;
self.onFulfilled.forEach(fn=>fn());//PromiseA 2.2.6.1
}
}
function reject(reason){
if(self.status===PENDING){
self.status = REJECTED;
self.reason = reason;
self.onRejected.forEach(fn=>fn());//PromiseA 2.2.6.2
}
}
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
// then必須返回一個(gè)promise
Promise.prototype.then = function(onFulfilled,onRejected){
// PromiseA 2.2.1/PromiseA 2.2.5/PromiseA 2.2.7.3/PromiseA 2.2.7.4
onFulfilled = typeof onFulfilled ==='function'?onFulfilled:value =>value;
onRejected = typeof onRejected === 'function'?onRejected:reason=>{throw reason};
let self = this;
//PromiseA 2.2.7
let Promise2 = new Promise((resolve,reject)=>{
if(self.status===FULFILLED){
//PromiseA 2.2.2
// Promise A 2.2.4----setTimeout
setTimeout(()=>{
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
//PromiseA 2.2.7.2
reject(e)
}
});
}else if(self.status === REJECTED){
// PromiseA 2.2.3
setTimeout(()=>{
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
}else if(self.status===PENDING){
self.onFulfilled.push(()=>{
setTimeout(()=>{
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
}
});
return promise2;
}
function resolvePromise(promise2,x,resolve,reject){
let self = this;
//PromiseA 2.3.1
if(promise2===x){
reject(new TypeError('changing cycle'));
}
if(x && typeof x ==="object"|| typeof x ==='function'){
let used;//PromiseA 2.3.3.3.3//只能調(diào)用一次
try{
let then = x.then;
if(typeof then === 'function'){
//PromiseA 2.3.3
then.call(x,(y)=>{
// PromiseA 2.3.3.1
if(used)return;
used = true;
resolvePromise(promise2,y,resolve,reject);
},(r)=>{
//PromiseA 2.3.3.2
if(used)return;
used = true;
reject(r)
});
}else{
//PromiseA 2.3.3.4
if(used)return;
used = true;
reject(x);
}
}catch(e){
//PromiseA 2.3.3.2
if(used)return;
used = true;
reject(e);
}
}else{
//PromiseA 2.3.3.4
resolve(x);
}
}
module.exports = Promise;
我們可以用專門的測(cè)試腳本測(cè)試所編寫的代碼是否符合PromiseA 的規(guī)范。
在上面的promise實(shí)現(xiàn)的代碼中,增加一下代碼
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
安裝測(cè)試腳本
npm install -g promises-aplus-tests
如果當(dāng)前的promise源碼的文件名為promise.js
那么在對(duì)應(yīng)的目錄執(zhí)行以下命令:
promises-aplus-tests promise.js
promises-aplus-tests中共有872條測(cè)試用例。以上代碼,可以完美通過(guò)所有用例。
本文借鑒自:https://blog.csdn.net/liuyan19891230/article/details/88385973
來(lái)源:https://www./content-1-311801.html
|