iT邦幫忙

2024 iThome 鐵人賽

DAY 16
2
Modern Web

JavaScript學習筆記系列 第 16

[Day 16] 非同步 Promise

  • 分享至 

  • xImage
  •  

如何建立Promise

const myPromise = new Promise(function (resolve, reject) {
  //resolve執行成功結果
  //reject執行失敗結果
});


function myPromise() {
  return new Promise(function (resolve, reject) {
    //resolve執行成功結果
    //reject執行失敗結果
  });
}

Promise基本宣告,也有看到放在funciton裡面return出來的方式。

Promise 的三種狀態

  • pending(待處理):初始狀態,不是fulfilled也不是reject。
  • fulfilled(成功):執行成功,並有一個success value。
  • rejected(失敗):執行失敗,並有一個failure reason。

MDN:
The eventual state of a pending promise can either be fulfilled with a value or rejected with a reason (error).

如果promise從pending變成setteld(已解決),代表有結果(fulfilled 或 rejected)。

這些狀態都會被記錄在Promise物件裡面,用開發者工具(DevTools)可以查看。

範例:

const myPromise = new Promise(function (resolve, reject) {
  if (true) {
    resolve("成功");
  } else {
    reject("失敗");
  }
});
console.log(myPromise);

可以看到new Promise後產生的會是一個Promise物件。
在裡面設if...else,如果成立則執行resolve(),反之執行reject(),
我先設定if的小括號為true,讓他執行resolve()並印出。

執行結果:
Promise狀態
展開myPromise這個物件查看內容,[[PromiseState]]顯示為fulfilled[[PromiseResult]]為我們帶入resolve的參數值。

但是[[PromiseState]][[PromiseResult]]無法取得,所以要透過then()函式取得結果,then()函式參數帶入的是callback function,而這個callback function的參數帶入的就是剛剛Promise的結果,這樣就可以做到等Promise執行完有結果了,之後再執行callback的順序。

Instance methods 實例方法

在看MDN發現的東東,之前只知道then()和catch()卻不知道有finally(),而這樣的組合讓我想到try...catch...finally這位朋友XD

先說說這三者的介紹:

then()

是 JavaScript 中處理 Promise 結果的主要方法,用來處理 Promise 的成功或失敗結果。它接受兩個callback function作為參數,分別對應 Promise完成(fulfilled)和失敗(rejected)。

語法

promise.then(fulfilled時執行的callback, rejected時執行的callback);

如果只要Promise的成功結果,可以只傳入第一個參數,第二個參數省略。一般錯誤處理(rejected)可透過 .catch()。

  • 一個then()裡面放兩個參數,一個接成功,一個接失敗範例:
const myPromise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve("成功結果");
  }, 1000);
});

myPromise.then(
  //第一個callback為fulfilled
  function (result) {
    console.log("成功:", result);
  },
  //第二個callback為rejected
  function (error) {
    console.log("失敗:", error);
  }
);

如果需要依序執行多個 promise的話,可以then()後面繼續串接then()。

補充:MDN說到 then()catch()finally()函式都會return a new Promise(回傳一個新Promise),因為then()會回傳一個新的Promise,所以就可以繼續使用then()方法。

  • 串接多個then()範例:
const myPromise = new Promise(function (resolve, reject) {
  resolve(2);
});

myPromise
  .then(function (result) {
    console.log("第一步結果:", result); //印出2
    return result * 2; // 回傳新結果給下一個 then
  })
  .then(function (result) {
    console.log("第二步結果:", result); //印出4
    return result * 2; // 回傳新結果給下一個 then
  })
  .then(function (result) {
    console.log("第三步結果:", result); //印出8
  });

catch()

專門用來捕捉錯誤。它會忽略成功的callback,只處理失敗(rejection)的情況

因為用then()的callback要處理成功,又要捕捉錯誤,程式碼會很長,所以透過catch()可以讓程式碼更簡潔。

範例:

const myPromise = new Promise(function (resolve, reject) {
  reject("發生錯誤");
});

myPromise
  .then(function (result) {
    console.log("成功:", result);
  })
  .catch(function (error) {
    console.log(error); // 印出 "發生錯誤"
  });

finally()

Promise不論結果如何都會執行裡面的程式碼它不會接收任何結果,只是單純執行callback,finally()的回傳值不會傳遞給後面的then(),因為 finally() 不會更改Promise的結果。

範例:

const myPromise = new Promise(function (resolve, reject) {
  let success = false;
  setTimeout(() => {
    if (success) {
      resolve("成功!");
    } else {
      reject("失敗!");
    }
  }, 1000);
});

myPromise
  .then(function (result) {
    console.log(result); // 成功的話會印出結果
  })
  .catch(function (error) {
    console.log("錯誤:", error); // 失敗的話會捕捉到錯誤並印出
  })
  .finally(function () {
    console.log("執行結束,無論成功與失敗都會執行"); // 無論結果如何,都會執行這一段
  });

小補充:因為Promise是一個物件,then()和catch()和finally()這些其實都是Promise的方法,用開發者工具就可以查看到,也就是為什麼Promise.then()或Promise.catch()是用「點」來接,因為使用了物件的「點記法」。之前都沒意識到,都死背XD

Promise物件的方法

Promise 拆解分析

一開始看Promise,我覺得then和catch因為裡面還有callback function,程式碼很長讓我常常看的頭腦當機...沒辦法快速解析/images/emoticon/emoticon06.gif

以下可以幫助閱讀更快速,謝謝Mentor教導,在此分享給大家:

const myPromise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    if (true) {
      resolve(100);
    } else {
      reject(0);
    }
  }, 1000);
});

//原先寫法
myPromise
  .then(function (result) {
    return result * 2; //新結果傳遞給下一個then
  })
  .catch(function (error) {
    return result * 3;
  })
  .finally(function () {
    console.log("不論如何都會執行finally");
    return `我是finally的return`;
  })
  .then(function (result) {
    return result * 4;
  });

頭腦先轉換成這樣理解:

//先轉換幫助理解
myPromise.then(funcA).catch(funcB).finally(funcC).then(funcD);

function funcA(result) {
  return result * 2;
}
function funcB(result) {
  return result * 3;
}
function funcC(result) {
  console.log("不論如何都會執行finally");
  return `我是finally的return`;
}
function funcD(result) {
  return result * 4;
}

把then()裡面的函式都先拿出來,並修改成具名函式funcAfuncBfuncCfuncD後再放入。

.then(funcA)

這樣的意思是funcA代表註冊而已,尚未執行,等到條件成立(Promise有fulfilled)就會呼叫它。

.then或是.catch裡面的程式碼就會簡潔許多~也比較好閱讀了

搭配return或throw

Promise的結束有兩種,一種最後return,一種最後throw。
測試結果return會跑then(),throw會跑catch()

範例:

const myPromise = new Promise(function (resolve, reject) {
  if (false) {
    resolve("成功");
  } else {
    throw "失敗";
  }
});

myPromise
  .then(function (result) {
    return result;
  })
  .catch(function (error) {
    return error;
  });

執行結果:
Promise搭配throw

小結

這次再研究Promise發現了一些之前沒注意到的事情,覺得有收穫~越來越了解它的運作,希望有幫助到大家。

以上分享~謝謝

參考資料

MDN - Promise
JS 原力覺醒 Day14 - 一生懸命的約定:Promise


上一篇
[Day 15] 同步與非同步 - 概念
下一篇
[Day 17] 非同步 Async / await 語法糖
系列文
JavaScript學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言