Promise 源碼記錄(上課過程記錄的筆記)
Promise.js代碼:
僅僅實現了簡單的then,catch和Promise對象的執行器函數
(function (window){ /** IIFE */
const PENDING ='pending';
const RESOLVED ='resolved';
const REJECTED = 'rejected';
function Promise(exector){
let self = this;
self.status = PENDING;
/**
* callbacks裏面存儲的數據類型爲:{onResolved,onRejected}
*/
self.callbacks = [];
self.data = undefined;
function resolve(value){
if(self.status === PENDING){
self.data = value;
self.status = RESOLVED;
if(self.callbacks.length > 0){
self.callbacks.forEach(callbackObj => {
setTimeout(() => {
callbackObj.onResolved(value);
});
});
}
}
}
function reject(reasen){
if(self.status === PENDING){
self.data = reasen;
self.status = REJECTED;
if(self.callbacks.length > 0){
self.callbacks.forEach(callbackObj => {
setTimeout(() => {
callbackObj.onRejected(reason);
});
});
}
}
}
try{
exector(resolve,reject);
}catch(error){
reject(error);
}
}
/**
* 定義Promise的then方法實現回調
*/
Promise.prototype.then = function(onResolved, onRejected){
/**首先定義兩個回調函數的形式
* 1. 如果兩個回調時函數,則直接返回
* 2. 如果兩個回調函數不是函數類型,強制其爲函數
*/
onResolved = typeof onResolved === 'function' ? onResolved : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reasen => {throw reason};
const self = this;
return new Promise((resolve, reject) => {
/** 直接將RESOLVED/REJECTED狀態下的執行器封裝成一個函數 */
function handle(callback){
/** 這裏要把執行函數放入異步隊列中 */
/**
* 此處要定義Promise的狀態,分爲三種情況
* 1. 拋出異常,直接執行reject
* 2. 返回的值是Promise,則新的Promise的結果和狀態由上一次的結果決定
* 3. 返回的值不是Promise,則新的Promise直接成功
*/
try {
const result = callback(self.data);
if(result instanceof Promise){
result.then(resolve, reject);
}else{
resolve(result);
}
} catch (reason) {
reject(reason);
}
}
/**
* 新的Promise的狀態要根據onResolved/onRejected的執行結果來決定
*/
if(self.status === RESOLVED){
setTimeout(() => {
handle(onResolved);
});
}else if(self.status === REJECTED){
setTimeout(() => {
handle(onRejected);
});
}else{
/**
* 如果是PENDING狀態,要把回調函數保存起來
* 但是不能直接去存,因爲要根據之前的結果來定義新的Promise的狀態
* 下面不需要異步調用,因爲異步操作在Promise的執行器中已經做了
*/
self.callbacks.push({
onResolved(){
handle(onResolved);
},
onRejected(){
handle(onRejected);
}
});
}
});
}
/** 定義catch方法 */
Promise.prototype.catch = function(onRejected){
this.then(undefined, onRejected);
}
/** 向外暴露Promise */
window.Promise = Promise
})(window)
測試用的index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Promise</title>
<script src="./Promise.js"></script>
</head>
<body>
<script type="text/javascript">
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5);
}, 3000);
});
p1.then(value => {
console.log("The anwser is successful, and the result is :", value);
return new Promise(() => {});
}).then(value => {
console.log("The next result is:", value);
}).catch(error => {
console.log("The error is :", error)
});
</script>
</body>
</html>