- 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>