我的promise能實作什麼?
1:解決回調地獄,實作異步
2:可以鍊式調用,可以嵌套調用
3:有等待态到成功态的方法,有等待态到失敗态的方法
4:可以衍生出周邊的方法,如Promise.resolve(),Promise.reject(),Promise.prototype.then(),Promise.prototype.catch(),Promise.all() // 所有的完成
- 可以根據自己的需求調節自己的promise
let PromiseA = require('./PromiseA');
const promiseA = new PromiseA((resolve, reject) => {
resolve(new PromiseA((resolve,reject)=>{
setTimeout(()=>{
resolve(100)
},1000)
}))
})
promiseA.then(data=>{
console.log(data)
下面開始實作promise,首先創造三個常量,等待,成功,失敗
const PENDING = 'PENDING'; // 等待狀态
const RESOLVED = 'RESOLVED'; // 成功狀态
const REJECTED = 'REJECTED'; // 失敗狀态
然後創造一個promiseA類,裡面有constructor,then方法,catch方法。這裡的catch其實就是失敗的then,即then(null,(err)=>{...})
class PromiseA {
constructor(){...}
then(){...}
catch(err){
return this.then(null,err)
}
}
我們重點關注constructor和then,先來看constructor。這裡promiseA預設的狀态是等待态,成功的值value預設為undefined,失敗的值reason預設為undefined。這裡的onResolvedCallbacks和onRejectedCallbacks是一個釋出訂閱的數組,我們先不管。然後有resolve方法,reject方法
還有Promise自帶一個executor執行器,就是傳進來的參數。會立即執行 。 但有可能出錯。是以用try,catch包住。 executor裡有倆個參數,就是resolve和reject。就是promise傳進來參數的倆個resolve,reject方法.
constructor(executor) {
this.status = PENDING; // 預設等待狀态
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if(value instanceof PromiseA){
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());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
然後我們在看看then,then裡面傳進來倆個參數,其實就是倆個方法。一個成功的回調,一個失敗的回調。我們重點看一下,三個狀态的執行,即status的走向。如果是resolve,即執行成功的回調onFulfilled。如果是reject,即執行失敗的回調onRejected。如果是等待,即執行一個釋出訂閱的模式,釋出訂閱,其實就是,我先将成功的回調或者的失敗的回調各自放入對應的數組,即是上面我們跳過的倆個數組onResolvedCallbacks和onRejectedCallbacks 。然後,當狀态改變為resolve或者reject的時候,即周遊執行對應的回調函數。至此異步就實作了,回調地獄解決。這個異步解決就是靠釋出訂閱模式來解決的。
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled:v=>v
onRejected = typeof onRejected === 'function' ? onRejected:e=>{throw e}
let promise2 = new PromiseA((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(err);
}
});
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(err);
}
});
})
}
})
return promise2;
}
接下來我們繼續實作鍊式調用,既是一個promiseA.then的結果傳回的e是promise2的then的data。 一個成功的結果傳回給下一個then作為參數。
let promise2 = promiseA.then(e=>{
return e
)
promise2.then(data=>{
console.log(data,'123')
那麼繼續實作,還是上面的函數。這裡我們重點觀察這個promise2和setTimeout和resolvePromise. 我們先說promise2,這裡的promise2,其實是一個新的promise.也就是說promise的鍊式調用靠的就是傳回一個新的promise.這裡把之前的三種狀态包起來,目的就是可以讓裡面得到的結果,擷取給promise2的resolve和reject。有人可能會說,那麼promise2的resolve或者reject要還是promise怎麼辦?這裡我們就要用到resolvePromise方法來判斷了。是以我們将成功的回調函數resolve換成resolvePromise方法來執行。這裡我們要明白,resolve是執行成功的回調函數。不管狀态是成功還是失敗,如果執行成功都是走向resolve。是以resolve和reject的狀态如果執行成功都是走向resolve。
let promise2 = new PromiseA((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
});
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(err);
}
});
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(err);
}
});
})
}
})
return promise2;
然後我們在看resolvePromise方法,走到這裡,說明是執行成功的回調函數了。傳進去的參數有promise2,x,promise2的resolve,promise2的reject。首先promise2是一個new promise。 這樣傳進去參數是會報錯的。因為執行到這一步,promise2還沒有生成。是以是會報錯的。
是以我們加一個setTimeout包住它,這樣就可以等promise2生成完在執行。這裡的setTimeout涉及到了事件循環,也就是宏任務和微任務的部分。js執行機制是先執行主線程,然後執行微任務隊列,然後進行渲染,然後在執行宏任務隊列。宏任務執行完,如果宏任務裡還包着js任務,就繼續循環反複。直到所有任務執行完成。這裡的setTimeout是宏任務,
resolvePromise(promise2, x, resolve, reject);
剛剛說到setTimeout,這裡貼上一段代碼。這裡的newPromise是在setTimeout前執行的。
console.log(1);
setTimeout(() => {
console.log("我是定時器,延遲0S執行的");
}, 0);
new Promise((resolve, reject) => {
console.log("new Promise是同步任務裡面的宏任務");
resolve("我是then裡面的參數,promise裡面的then方法是宏任務裡面的微任務");
}).then(data => {
console.log(data);
});
console.log(2);
好的參數都傳進去了,接下來我們看resolvePromise的具體方法。就是一個判斷回調函數x是不是promise,如果是就在循環拆開。直到不是為止。如果是普通值的話就可以直接傳回了。至此,是以的promise庫就實作完了。至于後面的all和其他周邊方法就是文法糖了。主要核心部分掌握了,後面的周邊方法就不算什麼了。
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('傳回的promise和目前promise不能是同一個對象哦,會嵌入死循環'))
}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x,y=> {
resolvePromise(promise2, y, resolve, reject)
},r=> {
reject(r)
}
)
} else {
resolve(x)
}
} catch (err) {
reject(err)
}
} else {
resolve(x);
}
至于resolve方法裡判斷,我們來看看。其實也是一個遞歸。判斷PromiseA裡的resolve裡面是不是promise,一直拆開。跟上面的方法類似。
let resolve = (value) => {
if(value instanceof PromiseA){
value.then(resolve,reject)
return
}
if (this.status === PENDING) {
this.value = value;
this.status = RESOLVED;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
而至于這倆行代碼,就是解決一個不斷向jquery那樣then的情況。如果是函數的話,将自己的參數作為結果傳回。傳遞給下一個then。
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled:v=>v
onRejected = typeof onRejected === 'function' ? onRejected:e=>{throw e}
promiseA.then().then().then().then().then()
原文位址
https://www.cnblogs.com/At867604340/p/12486678.html