
- Javascript 基礎教程
- Javascript - 首頁
- JavaScript - 路線圖
- JavaScript - 概述
- JavaScript - 特性
- JavaScript - 啟用
- JavaScript - 位置
- JavaScript - 語法
- JavaScript - Hello World
- JavaScript - Console.log()
- JavaScript - 註釋
- JavaScript - 變數
- JavaScript - let 語句
- JavaScript - 常量
- JavaScript - 資料型別
- JavaScript - 型別轉換
- JavaScript - 嚴格模式
- JavaScript - 保留關鍵字
- JavaScript 運算子
- JavaScript - 運算子
- JavaScript - 算術運算子
- JavaScript - 比較運算子
- JavaScript - 邏輯運算子
- JavaScript - 位運算子
- JavaScript - 賦值運算子
- JavaScript - 條件運算子
- JavaScript - typeof 運算子
- JavaScript - 空值合併運算子
- JavaScript - delete 運算子
- JavaScript - 逗號運算子
- JavaScript - 分組運算子
- JavaScript - yield 運算子
- JavaScript - 展開運算子
- JavaScript - 指數運算子
- JavaScript - 運算子優先順序
- JavaScript 控制流
- JavaScript - if...else
- JavaScript - while 迴圈
- JavaScript - for 迴圈
- JavaScript - for...in
- Javascript - for...of
- JavaScript - 迴圈控制
- JavaScript - break 語句
- JavaScript - continue 語句
- JavaScript - switch case
- JavaScript - 使用者自定義迭代器
- JavaScript 函式
- JavaScript - 函式
- JavaScript - 函式表示式
- JavaScript - 函式引數
- JavaScript - 預設引數
- JavaScript - Function() 建構函式
- JavaScript - 函式提升
- JavaScript - 自執行函式
- JavaScript - 箭頭函式
- JavaScript - 函式呼叫
- JavaScript - Function call()
- JavaScript - Function apply()
- JavaScript - Function bind()
- JavaScript - 閉包
- JavaScript - 變數作用域
- JavaScript - 全域性變數
- JavaScript - 智慧函式引數
- JavaScript 物件
- JavaScript - Number
- JavaScript - Boolean
- JavaScript - String
- JavaScript - Array
- JavaScript - Date
- JavaScript - DataView
- JavaScript - Handler
- JavaScript - Math
- JavaScript - RegExp
- JavaScript - Symbol
- JavaScript - Set
- JavaScript - WeakSet
- JavaScript - Map
- JavaScript - WeakMap
- JavaScript - 可迭代物件
- JavaScript - Reflect
- JavaScript - TypedArray
- JavaScript - 模板字面量
- JavaScript - 標籤模板
- 面向物件的 JavaScript
- JavaScript - 物件
- JavaScript - 類
- JavaScript - 物件屬性
- JavaScript - 物件方法
- JavaScript - 靜態方法
- JavaScript - 顯示物件
- JavaScript - 物件訪問器
- JavaScript - 物件建構函式
- JavaScript - 原生原型
- JavaScript - ES5 物件方法
- JavaScript - 封裝
- JavaScript - 繼承
- JavaScript - 抽象
- JavaScript - 多型
- JavaScript - 解構賦值
- JavaScript - 物件解構
- JavaScript - 陣列解構
- JavaScript - 巢狀解構
- JavaScript - 可選鏈
- JavaScript - 全域性物件
- JavaScript - Mixins
- JavaScript - 代理 (Proxies)
- JavaScript 版本
- JavaScript - 歷史
- JavaScript - 版本
- JavaScript - ES5
- JavaScript - ES6
- ECMAScript 2016
- ECMAScript 2017
- ECMAScript 2018
- ECMAScript 2019
- ECMAScript 2020
- ECMAScript 2021
- ECMAScript 2022
- JavaScript 非同步程式設計
- JavaScript - 非同步程式設計
- JavaScript - 回撥函式
- JavaScript - Promise
- JavaScript - Async/Await
- JavaScript - 微任務
- JavaScript - Promisification (Promise 化)
- JavaScript - Promise 鏈式呼叫
- JavaScript - 定時事件
- JavaScript - setTimeout()
- JavaScript - setInterval()
- JavaScript Cookie
- JavaScript - Cookie
- JavaScript - Cookie 屬性
- JavaScript - 刪除 Cookie
- JavaScript 瀏覽器 BOM
- JavaScript - 瀏覽器物件模型
- JavaScript - Window 物件
- JavaScript - Document 物件
- JavaScript - Screen 物件
- JavaScript - History 物件
- JavaScript - Navigator 物件
- JavaScript - Location 物件
- JavaScript - Console 物件
- JavaScript Web APIs
- JavaScript - Web API
- JavaScript - History API
- JavaScript - Storage API
- JavaScript - Forms API
- JavaScript - Worker API
- JavaScript - Fetch API
- JavaScript - Geolocation API
- JavaScript 事件
- JavaScript - 事件
- JavaScript - DOM 事件
- JavaScript - addEventListener()
- JavaScript - 滑鼠事件
- JavaScript - 鍵盤事件
- JavaScript - 表單事件
- JavaScript - Window/Document 事件
- JavaScript - 事件委託
- JavaScript - 事件冒泡
- JavaScript - 事件捕獲
- JavaScript - 自定義事件
- JavaScript 錯誤處理
- JavaScript - 錯誤處理
- JavaScript - try...catch
- JavaScript - 除錯
- JavaScript - 自定義錯誤
- JavaScript - 擴充套件錯誤
- JavaScript 重要關鍵字
- JavaScript - this 關鍵字
- JavaScript - void 關鍵字
- JavaScript - new 關鍵字
- JavaScript - var 關鍵字
- JavaScript HTML DOM
- JavaScript - HTML DOM
- JavaScript - DOM 方法和屬性
- JavaScript - DOM Document
- JavaScript - DOM 元素
- JavaScript - DOM 屬性 (Attr)
- JavaScript - DOM 表單
- JavaScript - 修改 HTML
- JavaScript - 修改 CSS
- JavaScript - DOM 動畫
- JavaScript - DOM 導航
- JavaScript - DOM 集合
- JavaScript - DOM NodeList
- JavaScript - DOM DOMTokenList
- JavaScript 其他
- JavaScript - Ajax
- JavaScript - 非同步迭代
- JavaScript - Atomics 物件
- JavaScript - rest 引數
- JavaScript - 頁面重定向
- JavaScript - 對話方塊
- JavaScript - 頁面列印
- JavaScript - 驗證
- JavaScript - 動畫
- JavaScript - 多媒體
- JavaScript - 圖片地圖
- JavaScript - 瀏覽器
- JavaScript - JSON
- JavaScript - 多行字串
- JavaScript - 日期格式
- JavaScript - 獲取日期方法
- JavaScript - 設定日期方法
- JavaScript - 模組
- JavaScript - 動態匯入
- JavaScript - BigInt
- JavaScript - Blob
- JavaScript - Unicode
- JavaScript - 淺複製
- JavaScript - 呼叫棧
- JavaScript - 引用型別
- JavaScript - IndexedDB
- JavaScript - 點選劫持攻擊
- JavaScript - 柯里化
- JavaScript - 圖形
- JavaScript - Canvas
- JavaScript - 防抖
- JavaScript - 效能
- JavaScript - 樣式指南
JavaScript - Promise 鏈式呼叫
JavaScript 中的Promise 鏈式呼叫即使使用單個 Promise 也能處理多個相關的非同步操作。單個 Promise 處理單個非同步操作,而 Promise 鏈式呼叫允許您建立一個 Promise 序列。其中,一個 Promise 的成功或失敗都會觸發下一個 Promise 的執行。這使您可以處理多個非同步操作。
在 JavaScript 中,我們可以使用 Promise() 建構函式生成 Promise 程式碼,並使用 then() 方法使用它。它處理單個非同步操作。要處理多個非同步操作,我們需要使用多個 Promise,如下例所示。
示例
在下面的程式碼中,我們定義了 promise1,它在 1 秒後被 resolved。我們還定義了全域性變數“data”。
之後,我們使用 then() 方法使用 promise1,並在回撥函式中將 Promise 的返回值儲存在 data 中。
接下來,我們定義了 promise2,它在 2 秒後被 resolved。接下來,我們使用 then() 方法和 promise2,並在回撥函式中使用了“data”變數。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); var data; // First promise let promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(10); }, 1000); }); promise1.then((value) => { data = value; // Stroing value into the data output.innerHTML += "The promise1 is resolved and data is: " + data + "<br>"; }); // Second promise let promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve(20); }, 2000); }); promise2.then((value) => { data = data * value; // Using the data from the first promise output.innerHTML += "The promise2 is resolved and data is: " + value + "<br>"; output.innerHTML += "The final value of the data is: " + data + "<br>"; }); </script> </body> </html>
輸出
The promise1 is resolved and data is: 10 The promise2 is resolved and data is: 20 The final value of the data is: 200
在上面的示例中,我們建立了兩個不同的 Promise 來對 promise1 返回的資料執行多個操作。
這增加了程式碼的複雜性並降低了可讀性。
這時,Promise 鏈式呼叫就派上用場了。
JavaScript Promise 鏈式呼叫
JavaScript 中 Promise 鏈式呼叫的概念允許您使用單個 Promise 執行多個相關的非同步操作。
您可以在使用 Promise 時使用多個 then() 方法來執行多個非同步操作。
語法
JavaScript 中 Promise 鏈式呼叫的語法如下:
Promise .then(callback); .then(callback); ... .then(callback);
在上述語法中,我們使用了多個 then() 方法來處理多個非同步操作。每個 then() 方法都執行單個回撥函式。
示例
在下面的程式碼中,我們定義了 promise1。之後,我們使用 Promise 鏈來執行多個非同步操作。
在第一個 then() 方法中,我們在乘以 2 後返回該值。在下一個 then() 方法中,我們列印更新後的值,並在乘以 2 後返回新值。我們在第三個 then() 方法中也執行了類似的操作。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); const promise1 = new Promise((resolve, reject) => { resolve(2); }); // Promise chaining promise1 .then((value) => { output.innerHTML = "The square of 2 is " + value * 2 + "<br>"; return value * 2; // Returning a promise for next then() method }) .then((value) => { output.innerHTML += "The square of 4 is " + value * 2 + "<br>"; return value * 2; }) .then((value) => { output.innerHTML += "The square of 8 is " + value * 2 + "<br>"; }); </script> </body> </html>
輸出
The square of 2 is 4 The square of 4 is 8 The square of 8 is 16
多個 Promise 處理程式
您還可以使用多個 Promise 處理程式來使用單個 Promise。但是,如果您使用多個 Promise 處理程式,則它不被視為 Promise 鏈式呼叫。
示例
在下面的程式碼中,我們建立了 promise1。
之後,我們使用多個 Promise 處理程式來使用該 Promise。每個 Promise 處理程式都分別解決該 Promise。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); const promise1 = new Promise((resolve, reject) => { resolve(2); }); promise1 .then((value) => { output.innerHTML += "Inside the first promise handler. <br>"; return value * 2; }) promise1 .then((value) => { output.innerHTML += "Inside the second promise handler. <br>"; return value * 2; }) promise1 .then((value) => { output.innerHTML += "Inside the third promise handler. <br>"; return value * 2; }) </script> </body> </html>
輸出
Inside the first promise handler. Inside the second promise handler. Inside the third promise handler.
使用 Promise 鏈式呼叫進行錯誤處理
您可以使用 catch() 方法與 Promise 鏈式呼叫結合來處理錯誤。
如果您在所有 then() 方法之後最後使用 catch() 方法,它會捕獲任何 then() 方法中的錯誤並進行處理。如果您在 then() 方法之間使用 catch() 方法,它會捕獲之前 then() 方法中的錯誤。
讓我們透過下面的示例來了解它。
示例
在下面的程式碼中,我們定義了 Promise 並將其 rejected。
之後,我們使用 Promise 鏈式呼叫來使用該 Promise。我們使用了兩個 then() 方法和一個在所有 then() 方法之後的 catch() 方法。
在輸出中,您可以看到,由於我們 rejected 了 Promise,因此控制權進入了 catch() 方法。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); const promise1 = new Promise((resolve, reject) => { reject("There is an error."); }); promise1 .then((value) => { output.innerHTML += "The returned value is: " + value + "<br />"; return value + " Everything is fine!"; }) .then((value) => { output.innerHTML += value; }) .catch((error) => { output.innerHTML += error; }); </script> </body> </html>
輸出
There is an error.
返回 Promise
當您從 then() 方法返回值時,它會預設返回 Promise 並使用返回值解析它,因為它是一個非同步方法。
但是,您可以手動返回 Promise 來拒絕 Promise 或執行任何其他操作。
示例
在下面的程式碼中,我們定義了 promise1,並在回撥函式中使用了 setTimeOut() 方法。
之後,我們使用多個 then() 方法使用該 Promise。在每個 then() 方法中,我們都返回一個新的 Promise。
如果只返回`then()`方法的值,它會返回一個立即解析的Promise。但如果需要新增一些延遲,則可以從`then()`方法返回Promise。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve("Stage 1"); }, 500); }); promise1 .then((value) => { output.innerHTML += value + "<br />"; return new Promise((resolve, reject) => { setTimeout(() => { resolve("Stage 2"); }, 1000); }); }) .then((value) => { output.innerHTML += value + "<br />"; return new Promise((resolve, reject) => { setTimeout(() => { resolve("Stage 3"); }, 200); }); }) .then((value) => { output.innerHTML += value + "<br />"; output.innerHTML += "Finished"; }) </script> </body> </html>
輸出
Stage 1 Stage 2 Stage 3 Finished
將巢狀回撥函式轉換為Promise鏈
在“JavaScript-callbacks”章節中,你學習了巢狀回撥函式。由於其複雜的語法,它也被稱為回撥地獄。
在這裡,我們將學習如何將回調地獄轉換為Promise鏈,使其更易於閱讀。
讓我們來看一個巢狀回撥函式的例子。
巢狀回撥函式
示例
在下面的程式碼中,`updateData()`函式將資料作為第一個引數,回撥函式作為第二個引數。
`updateData()`函式在1000毫秒後呼叫回撥函式,並將資料作為引數傳遞。
接下來,我們呼叫了`updateData()`函式,並將10作為第一個引數,匿名函式作為回撥函式。
回撥函式將結果值儲存到p中,方法是將1新增到’num1’值。
接下來,我們在回撥函式內部呼叫`updateData()`函式。我們也傳遞了資料和回撥函式作為引數。這樣,我們就定義了巢狀回撥函式。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); output.innerHTML += "Wait for updating the data...<br>"; // Callback hell function updateData(data, callback) { setTimeout(() => { callback(data); }, 1000); } updateData(10, function (num1) { let p = 1 + num1; updateData(30, function (num2) { let q = 1 + num2; updateData("The numeric value is: " + (p + q), function (answer) { output.innerText += answer; }); }); }); </script> </body> </html>
輸出
Wait for updating the data... The numeric value is: 42
現在,讓我們學習如何將上面的例子轉換為Promise鏈。
將巢狀回撥函式轉換為Promise鏈
示例
在下面的程式碼中,`updateData()`函式返回單個Promise。
之後,我們使用了Promise鏈,它是上面示例中定義的回撥地獄的替代方案。
<html> <body> <div id = "output"> </div> <script> let output = document.getElementById("output"); output.innerHTML += "Wait for updating the data...<br>"; function updateData(data) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(data); }, 1000); }); } updateData(10) .then((num1) => { let p = 1 + num1; return updateData(p); }) .then((num2) => { let q = 31; return updateData("The final value is: " + (num2 + q)); }) .then((res) => { output.innerText += res; }); </script> </body> </html>
輸出
Wait for updating the data... The final value is: 42
Promise鏈的即時示例
在即時開發中,您可以使用Promise鏈來獲取資料並在資料上執行操作。
示例
在下面的程式碼中,當用戶點選“獲取資料”按鈕時,它會呼叫`fetchData()`函式。
在`fetchData()`函式中,我們使用了`fetch()` API從API獲取資料。
之後,我們使用`then()`方法將資料轉換為JSON。
接下來,我們再次使用`then()`方法列印JSON資料。
<html> <body> <button onclick = "fetchData()"> Fetch Data </button> <div id = "output"> </div> <script> let output = document.getElementById("output"); function fetchData() { fetch('https://jsonplaceholder.typicode.com/todos/1') .then(response => response.json()) // Promise chaining .then((data) => { output.innerHTML += "The data is - " + JSON.stringify(data); }) } </script> </body> </html>
輸出
