Skip to main content

實作 Promise methods

什麼是 Promise

A Promise is an object representing the eventual completion or failure of an asynchronous operation Promise 是一個表示非同步運算的最終完成或失敗的物件

如何創建 Promise

使用 new 關鍵字創建,接受一個函式為參數,這個函式又稱為 executor,executor 會立即執行。executor 函式,會再接受另外兩個函式參數: resolve 成功調用的函式、reject 失敗時調用的函式

new Promise((resolve, reject) => {
console.log("executor 立即執行"); // executor 立即執行
});
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url === "www.google.com") {
resolve("hello google");
} else {
reject("it is not google");
}
}, 3000);
});
}

// 請求成功
requestData("www.google.com").then((res) => {
console.log(res); //hello google
});

// 請求失敗
requestData("www.yahoo.com").catch((e) => console.log(e)); //it is not google

Promise 的狀態

一個 Promise 一定會處於以下三種狀態的其中一種

  • pending:初始狀態,執行了 executor,但還在等待中。
  • fulfilled:表示操作完成,執行 resolve 函式。
  • rejected:表示操作失敗,執行 reject 函式。

Promise 方法

  • Promise.all(): 當所有 Promises 都成功時,回傳包含所有 Promise resolve 的陣列; 如果任何一個 Promise 被拒絕,立刻回傳 reject 的 Promise
  • Promise.race(): 回傳第一個 resolve/reject 的 Promise。即使其他 Promise 未完成,只要有一個完成,就會立刻回傳 resolve/reject 的結果
  • Promise.any(): 回傳第一個 resolve 的 Promise。倘若所有 Promise 都失敗,則回傳 reject 的 Promise
  • Promise.allSettled(): 所有 Promise 都完成後,回傳包含所有結果(resolve/reject)的 Promise 陣列

實作 Promise.all()

  • 接受多個 Promise 物件的 Iterable,例如:Array、Map、Set
  • 如果 Iterable 為空,則 fulfilled 值為空陣列
  • 如果 Iterable 不為空,則:
    • 所有 promises 都 fulfilled ⇒ 依序回傳 fulfilled 的值
    • 有任一個 promise 被 rejected ⇒ 立刻回傳 reject
  • 若不是 Promise 物件,則自動使用Promise.resolve方法來轉換
function promiseAll(promises) {
// 判斷輸入是否為 Iterable
const isIterable =
((typeof promises === "object" && promises !== null) ||
typeof promises === "string") &&
typeof promises[Symbol.iterator] === "function";

// 不是的話就回傳錯誤訊息
if (!isIterable) {
return new TypeError("Arguments must be iterable");
}

// 把 Iterable 轉成 Array
promises = Array.from(promises);

// 如果輸入是空的,就 resolve 一個空陣列
if (!promises.length) {
return Promise.resolve([]);
}
// 先宣告一個最終要 resolve 的 outputs,
// 之後每個 promise 被 fulfilled 時,就放到 outputs 裡面
const outputs = [];

// 紀錄有多少個 promise 已經 fulfilled
let resolveCounter = 0;

// Promise.all() 最終要回傳一個 promise
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
//考量p可能不一定是promise,也可能是常數
Promise.resolve(p)
.then((value) => {
// 當輸入的每個 promise 成功 fulfilled 時,就放到 outputs
// 透過 index,我們可以確保順序正確
outputs[index] = value;
// 每次成功放入 outputs 時,counter 要加一
resolveCounter += 1;
// 當 counter 等於 promises 長度時,代表所有的 promise 都 fulfilled
// 這時最外面的 promise 就可以 resolve
if (resolveCounter === promises.length) {
resolve(outputs);
}
})
.catch((e) => {
// 只要有一個被 reject 就馬上 reject
reject(e);
});
});
});
}

實作 Promise.race()

  • 接受多個 promises 的 Iterable,例如:Array、Map、Set
  • 回傳最先 fulfill 或最先被 reject 的那個 Promise 值
  • 如果 Iterable 為空,則回傳的 promise 物件為 pending
function promiseRace(promises) {
// 判斷輸入是否為 Iterable
const isIterable =
((typeof promises === "object" && promises !== null) ||
typeof promises === "string") &&
typeof promises[Symbol.iterator] === "function";

// 不是的話就回傳錯誤訊息
if (!isIterable) {
return new TypeError("Arguments must be iterable");
}

return new Promise((resolve, reject) => {
promises.forEach((p) => {
Promise.resolve(p)
.then((val) => {
// 只要有 fulfill 的,就馬上 resolve
resolve(val);
})
.catch((e) => {
// 或是只要有 reject 的,就馬上 reject
reject(e);
});
});
});
}