Promise 和 async & await

Promise 和 async & await

异步是为了优化需要长时间操作。异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。

回调函数

回调函数表明异步操作已经完成。作为曾经 JavaScript 中实现异步函数的主要方式。主要存在以下几个不足:

  • 错误处理困难:当任务长期运行,调用回调函数的代码一般不会和开始任务中的同步代码位于同一事件循环周期

  • 连续执行步骤非常棘手:也就是回调地狱的问题

  • 执行并行任务时也有一定复杂度

当异步请求相互依赖时使用回调的方式会导致深度嵌套,会导致经典的回调地狱:

1
2
3
4
5
6
7
8
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);

Promise

Promise 是现在 JavaScript 异步编程的基础。**** 对象用于表示一个异步操作的最终完成(或失败)及其结果值。

Promises/A+ 规范

Promise 作为异步编程的一种解决方案,它由社区最早提出和实现。ES6 增加了对 Promises/A+ 规范的完善支持,将其写进了语言标准,统一了用法,原生提供了Promise对象。

Promise 基础

Promise 有下面三种状态:

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。

  • 已兑现(**:意味着操作成功完成。

  • 已拒绝(**:意味着操作失败。

待定状态的 Promise 对象要么会通过一个值被兑现,要么会通过一个原因(错误)被拒绝。当这些情况之一发生时,我们用 promise then 方法排列起来的相关处理程序就会被调用。且过程是不可逆的,一个 promise 只能成功或失败一次。

promise

📌Promise 的状态是私有的,而且状态也不能被外部代码修改。Promise 特意将异步行为封装起来,从而隔离外部的同步代码。

使用Promise 有以下约定:

  • 在本轮 事件循环 运行完成之前,回调函数是不会被调用的。

  • 即使异步操作已经完成(成功或失败),在这之后通过 then() 添加的回调函数也会被调用。

  • 通过多次调用 then() 可以添加多个回调函数,它们会按照插入顺序进行执行。

Promise() 构造器

**** 构造器主要用于包装不支持 promise(返回值不是 Promise)的函数。构造器接受一个名为 “executor function“ 的函数。这个函数应当接受两个函数参数。当异步任务成功时,第一个函数(resolve)将被调用,并返回一个值代表成功。当其失败时,第二个函数(reject)将被调用,并返回失败原因(失败原因通常是一个 error 对象)。语法如下:

1
2
new Promise(executor)

一个简单的示例:

1
2
3
4
5
6
const await = (ws) => new Promise((resolve, reject) => {
if (typeof ws !== 'number') {
reject(Error('ws must be a number.'));
}
setTimeout(resolve, ws);
});

Promise 的实例方法

下面的方法返回的是一个 promise,所以都是可以被链式调用(chaining)。

  • Promise.prototype.then 

    为 promise 添加被兑现和被拒绝状态的回调函数,其以回调函数的返回值兑现 promise

  • Promise.prototype.catch

    被拒绝状态的回调函数,若回调函数被调用,则兑现其返回值,否则兑现原来的 promise 兑现的值

  • Promise.prototype.finally()

    将在原 promise 被敲定(无论被兑现还是被拒绝)时被调用

catch(failureCallback)then(null, failureCallback) 的缩略形式。一遇到异常抛出,浏览器就会顺着 Promise 链寻找下一个 onRejected 失败回调函数或者由 .catch() 指定的回调函数。onRejected 处理程序返回的值也会被 Promise.resolve() 包装。

静态方法

Promise.resolve()Promise.reject() 是手动创建一个已经 resolve 或者 reject 的 Promise 快捷方法。

Promise.all()Promise.race() 是并行运行异步操作的两个组合式工具。

Promise 扩展

ES6 的 Promise 实现有两个特性并没有实现:Promise 取消和进度跟踪。

async/await

异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

asyncawait关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise

  • async 函数的返回值是一个 Promise 对象。这个 promise 要么会通过一个由 async 函数返回的值被解决,要么会通过一个从 async 函数中抛出的(或其中没有被捕获到的)异常被拒绝。

  • await 操作符用于等待一个Promise 对象。它只能在异步函数 async function 中使用。

参考

https://book.douban.com/subject/35175321/

https://book.douban.com/subject/30143702/

https://web.dev/i18n/zh/promises/

https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await

https://es6.ruanyifeng.com/#docs/promise

Author

gyzhao

Posted on

2020-08-09

Updated on

2022-08-23

Licensed under

Comments