一、自定義Promise
Promise.js檔案
/**
* 自定義Promise函數子產品: ES5如何自定義子產品?IIFE 匿名函數自調用;函數自調用
*/
(function(window) {
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
/**
* Promise 構造函數 ;excutor 執行器函數 (同步執行);
*/
function Promise(excutor) {
// 将目前promise對象儲存起來;
const self = this;
self.status = PENDING; // 給promsie指定status,初始為pendding;
self.data = undefined; // 給promise指定一個存儲資料的屬性
self.callbacks = []; // 每個元素的結構:{onResolved(){},onRejected(){}}
/** 用于改變promise狀态 */
function resolve(value) {
// 如果目前狀态不是pending,直接結束;因為 狀态隻能改變一次,status為pending的時候,才能繼續往下執行;
if (self.status !== PENDING) return;
// 1. status狀态改為resolved
self.status = RESOLVED;
// 2. 儲存value資料
self.data = value;
// 如果有待執行的callback函數,立即異步執行(需放入隊列中,這裡借助setTimeout)回調函數onResolved;
if (self.callbacks.length > 0) {
setTimeout(() => {
// 放入隊列中,執行所有成功的回調
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value);
});
});
}
}
function reject(reason) {
// 如果目前狀态不是pending,直接結束;因為 狀态隻能改變一次,status為pending的時候,才能繼續往下執行;
if (self.status !== PENDING) return;
// 1. status狀态改為rejected
self.status = REJECTED;
// 2. 儲存value資料
self.data = reason;
// 如果有待執行的callback函數,立即異步執行(需放入隊列中,這裡借助setTimeout)回調函數onResolved;
if (self.callbacks.length > 0) {
setTimeout(() => {
// 放入隊列中,執行所有成功的回調
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason);
});
});
}
}
// 立即同步執行excutor
try {
excutor(resolve, reject);
} catch (error) {
reject(error); // 如果執行器抛出異常,promise變為失敗狀态,故調用reject
}
}
/**
* Promise原型對象的方法then();
* 指定成功或者失敗的回調
* 傳回一個promise對象
*/
Promise.prototype.then = function(onResolved, onRejected) {
const self = this;
// 指定回調函數的預設值,調用.then的時候,可能不執行onRejected
onResolved = typeof onResolved === "function" ? onResolved : value => value; // 向後傳遞成功的value
onRejected =
typeof onRejected === "function"
? onRejected
: reason => {
throw reason; // 指定預設的失敗的回調,将異常傳下去;(實作錯誤/異常傳透);向後傳遞失敗的reason
};
// 傳回一個新的promise
return new Promise((resolve, reject) => {
function handler(callback) {
// 根據執行的結果,改變return的promise狀态;
/**
* onResolved或者onRejected 的結果有三種情況:
* 1.抛出異常,return的promise就會失敗,狀态為rejected狀态,reason就是error
* 2.傳回一個非promise,return的promise就會成功,狀态為resolved狀态,value就是傳回的值;
* 3.傳回一個promise,return的promise的結果就是該promise的結果;
*/
try {
const result = callback(self.data);
if (result instanceof Promise) {
// result.then(
// value => {
// resolve(value);
// },
// reason => {
// reject(reason);
// }
// );
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
if (self.status === PENDING) {
// pending,将回調函數存起來,等待被執行;并讓它影響return的promise的狀态;
self.callbacks.push({
onResolved(value) {
// value,這個參數要不要都可
handler(onResolved);
},
onRejected(reason) {
handler(onRejected);
}
});
} else if (self.status === RESOLVED) {
// resolved,異步執行onResolved函數,并改變return的promise狀态;
setTimeout(() => {
handler(onResolved);
});
} else {
// rejected,異步執行onRejected函數
setTimeout(() => {
handler(onRejected);
});
}
});
};
/**
* Promise 原型對象的catch()方法;
* 指定失敗的回調;
* 傳回一個promise
*/
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected);
};
// Promise原型鍊上的方法finally(onFinally) ;無論promise是fulfilled或者是rejected,都會執行指定的回調函數onFinally
/**
*本質上是有個then方法;且finally要在要在promise狀态改變之後才執行
* 傳回promise,傳回的promsie的成功與否,取決于onFinally的結果;
* 而onFinally的執行結果,應該取決于前一個p 或者.then的執行結果;
* 這裡有個很重要的點,finally表示的是一定會執行,但并不一定是最後執行;
* 是以在finally中,應該将p的value或者reason向後傳遞下去;
*/
Promise.prototype.finally = function(onFinally) {
onFinally = typeof onFinally === "function" ? onFinally : function() {};
return this.then(
value => {
return Promise.resolve(onFinally()).then(() => value); // 向後傳遞成功的value (調用finally的promsie的成功的value)
},
reason => {
return Promise.resolve(onFinally()).then(() => {
// 實作異常傳透;向後傳遞失敗的reason
throw reason;
});
}
);
};
/**
* Promise 函數對象的resolve方法;
* 傳回一個成功或者失敗的promise
*/
Promise.resolve = function(data) {
/**
* 1. 如果接收的是一般值,promise成功,value就是這個值;
* 2. 如果結束皮的是成功的promise,則promise成功,value是該promise的value;
* 3. 如果接收的是一個失敗的promsie,則promsie失敗,reason是該promsie的reason
*/
return new Promise((resolve, reject) => {
if (data instanceof Promise) {
data.then(resolve, reject);
} else {
resolve(data);
}
});
};
/**
* Promise 函數對象的reject方法;
* 傳回指定結果的一個失敗的promise;
*/
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
};
/**
* Promise 函數對象的all(promises)方法;promises數組中的元素并不一定都是promsie,也可能隻是一個普通的值,如:5
* 傳回一個promise,當所有的promise都成功的時候,該promise 才是成功狀态;如果成功,傳回所有成功的promise;如果失敗,傳回失敗的reason;
*/
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
const values = new Array(promises.length); // 建立一個和promises長度相同的values數組;用于儲存成功的value 資料;
let count = 0; // 用來儲存成功的promsie的個數
// 周遊promises擷取每個promise的結果
promises.forEach((p, index) => {
// 這裡将的p不一定是一個promsie,故需将其包裝成一個promsie;如果它是一個promsie,再包一層也無所謂; Promise.resolve(p)
Promise.resolve(p).then(
value => {
count++;
// 把value按順序放入values中;;将value放入values中,且這裡存的順序應和傳入的promsies中的順序一緻;(數組中的元素和傳入all方法中的promsies中的順序是一樣的)
values[index] = value;
// 所有的成功了,将return的promise改為成功;
if (promises.length === count) {
resolve(values);
}
},
reason => {
reject(reason);
}
);
});
});
};
/**
* Promise函數對象的race方法;
* 傳回一個promise,傳回最先完成的那個promise,無論他成功還是失敗;
*/
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
// 周遊promises擷取每個promise的結果;因為promise的狀态隻能改變一次,故,隻有第一次調用才有效果;
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
// 一旦有成功,就将return變為成功;
resolve(value);
},
reason => {
// 一旦失敗,将return 變為失敗
reject(reason);
}
);
});
});
};
/**
* Promise 函數對象的any(promises)方法;
* 傳回第一個成功狀态的promise;如果都失敗,傳回 AggregateError: All promises were rejected
*/
Promise.any = function(promises) {
return new Promise((resolve, reject) => {
let count = 0; // 記錄失敗的promsie個數
promises.forEach((p, index) => {
Promise.resolve(p).then(
value => {
resolve(value);
},
reason => {
count++;
if (count === promises.length) {
reject("AggregateError: All promises were rejected");
}
}
);
});
});
};
/**
* Promsie 函數對象的allSettled(promises)方法;
* 傳回一個promise,當所有的promise都是已敲定狀态的時候,傳回一個promise,并帶有一個對象數組,
* 該對象數組是所有settled的promise的資訊;
* 否則無傳回;
*/
Promise.allSettled = function(promises) {
return new Promise((resolve, reject) => {
const values = new Array(promises.length); // 裝所有settled的promsie
let count = 0; // 定義已經settled的promsie的個數
promises.forEach((p, index) => {
Promise.resolve(p)
.then(
value => {
values[index] = {
status: "fulfilled",
value: value
};
},
reason => {
values[index] = {
status: "rejected",
reason: reason
};
}
)
.then(value => {
// promise是settled狀态的時候,才會進入這個then
count++;
if (count === promises.length) {
resolve(values);
}
});
});
});
};
// 自定義兩個函數:resolveDelay和rejectDelay;
/**
* 傳回一個promise對象,在指定時間過後,才确定promise結果
*/
Promise.resolveDelay = function(value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
}, time);
});
};
// 傳回一個promise對象,在指定時間過後,才失敗
Promise.rejectDelay = function(reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason);
}, time);
});
};
// 向外暴露Promise函數
window.Promise = Promise;
})(window);
二、引入剛剛的Promise.js進行測試
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Promise</title>
</head>
<body>
<h1>test</h1>
<!-- 引入自定義的Promise.js檔案 -->
<script src="./lib/Promise.js"></script>
<script>
const p1 = Promise.resolve(1);
const p2 = Promise.reject(2);
const pAll = Promise.all([p1, p2, 999]);
pAll
.then(value => {
console.log("value:", value);
})
.catch(reason => {
console.log("reason:", reason);
});
// 以上代碼的列印結果:reason: 2
</script>
</body>
</html>