系列文章
- Promise源碼解密-PromisesA+标準
- Promise源碼解密-同步版
- Promise源碼解密-異步版
- Promise源碼解密-then的鍊式調用
- Promise源碼解密-catch/resolve/reject/race
創作不易 拒絕白嫖 點個贊呗
關注專欄
Promise源碼解密 ,帶你走進Promise的深處!!!
then的用法
- 通過return 給下一個then傳值,成功/失敗的傳回值,最後都是傳到下一個then的成功會回調
let t = new Promise((resolve, reject) => {
console.log(a) // 執行console會報錯,最終隻會執行reject
})
t.then((res)=>{
return res
},error=>{
return error
}).then(
(res) => {
console.log(res.toString(),'res===='); // ReferenceError: a is not defined res====
},
(error) => {
console.log(error);
}
);
- then中的onFulfilled/onReject 是可選的, 下面的例子,第一個then沒有return值,但是第二個then也可以接受到值,最終輸出 then 回調可選。
let t = new Promise((resolve, reject) => {
resolve('then 回調可選')
})
t.then().then(
(res) => {
console.log(res);
},
(error) => {
console.log(error);
}
);
- 執行個體不可 循環引用,報錯 : Chaining cycle detected for promise #
let p = new Promise((resolve, reject) => {
resolve('不可循環引用')
})
var p2=p.then(()=>{
return p2 // 傳回的值還是p2
})
完整代碼
// 定義狀态常量
const STATUS_PENDING = "pending";
const STATUS_FULFILLED = "fulfilled";
const STATUS_REJECTED = "rejected";
function resolvePromise(promise2, x, resolve, reject) {
// 用來儲存是否已經reject或者resolve過
let called
if (promise2 === x) {
throw new TypeError('Chaining cycle detected for promise')
}
// 如果是函數或者object的話先預設是promise
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
// 如果then是函數的話
if (typeof then === 'function') {
// 為啥不直接x.then()
// 因為then已經判斷過是不是function,但是x.then沒有判斷過
// 就讓then執行 第一個參數是this 後面是成功的回調 和 失敗的回調
// 這裡的y是啥,如果x是promsie的話,那麼y就是x中的resolve/reject的值
then.call(x, y => {
// 成功和失敗隻能調用一個
if (called) return;
called = true;
console.log(y, 'yyyyyyyyyyyy')
// resolve的結果依舊是promise 那就繼續解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失敗隻能調用一個
if (called) return;
called = true;
reject(err);
})
} else {
resolve(x); // 如果不是函數,那就直接傳回結果
}
} catch (error) {
// 成功和失敗隻能調用一個
if (called) return;
called = true;
// 沒有then 不是函數也不是普通值
reject(error)
}
} else {
// x 是一個普通值
resolve(x)
}
}
class MyPromise {
// 接收一個 執行器
// new Promise的時候,執行器立即執行,
// 執行的時候根據指定函數執行
// 并且程式報錯的情況下
constructor(executor) {
this.status = STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
// 這裡的兩個資料,相當于訂閱者的籃子,then相當于訂閱者,接收到釋出者的函數,儲存在籃子裡
this.onFulfilledCallBacks = [];
this.onRejectCallBacks = [];
try {
// 這裡将傳入的resolve和reject變為類中的調用的話。
// (resolve, reject) => {
// resolve("then鍊式調用");=>this.resolve(then鍊式調用)
// }
executor(this.resolve, this.reject);
} catch (error) {
// 報錯的話直接将錯誤原因作為reason
this.reject(error);
}
}
// 這裡為啥使用箭頭函數而不是resolve(){}
// 這是因為上面的executor調用的時候,resolve中的this其實是undefined
// executor單獨調用了resolve/reject 這時,這兩個方法存在于執行是的環境,this不再指向執行個體
// 箭頭函數内部的this總是指向定義時所在的對象
resolve = (value) => {
// 判斷狀态是不是
if (this.status === STATUS_PENDING) {
console.log("執行resolve");
// 這裡接收傳進來的結果
this.value = value;
this.status = STATUS_FULFILLED;
this.onFulfilledCallBacks.forEach((fn) => {
fn();
});
}
};
reject = (reason) => {
if (this.status === STATUS_PENDING) {
console.log("執行reject");
// 這裡接收傳進來的錯誤的結果
this.reason = reason;
this.status = STATUS_REJECTED;
// 這裡相當于釋出的動作
this.onRejectCallBacks.forEach((fn) => {
fn();
});
}
};
then(onFulfilled, onReject) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onReject = typeof onReject === "function" ? onReject : (reason) => reason;
console.log("執行then時的狀态: ", this.status);
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === STATUS_FULFILLED) {
// 這個地方使用settimeout的目的是擷取到promise2。因為setTimeout是異步的,
// 會等到指派給promise2結束後才執行,
// 這裡的resolvePromise的作用是為了區分x是普通值還是新的promise還是函數
// 如果直接resolve(x)的話會導緻,輸出的是[object Object] res====,并不是想要的值
setTimeout(() => {
// 這裡try進行了捕獲異常,在最外面的executor不是進行了捕獲了?
// 這是因為異步裡面的方法不會被最外層的那個捕獲到
try {
console.log("執行 onFulfilled");
// 這裡的x是啥? 是then中回調的return的傳回值
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === STATUS_REJECTED) {
setTimeout(() => {
try {
console.log("執行 onReject");
let x = onReject(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === STATUS_PENDING) {
this.onFulfilledCallBacks.push(() =>
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
);
this.onRejectCallBacks.push(() =>
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
);
}
});
return promise2;
}
}
// 下面的函數相當于釋出者
let t = new MyPromise((resolve, reject) => {
// 指定執行哪個,resolve和reject最終隻會執行一個
// console.log(a) // 執行console會報錯,最終隻會執行reject
// // resolve("res")
// reject('reject')
// setTimeout(() => {
resolve("then鍊式調用");
// }, 1000)
});
t.then(() => {
return new MyPromise((resolve) => {
console.log(2);
setTimeout(() => {
resolve(3);
}, 3000);
});
}).then(
(res) => {
console.log(res.toString(), "res====");
},
(error) => {
console.log(error);
}
);