彻底搞清 JavaScript Promise
基本用法
我们知道,一个 js Promise 对象,我们可以用 then()、catch()、finally() 进行链式操作,如:
1 | promiseObj.then((res) => { |
这是 js Promise 的基本使用,但是要用好 Promise,还有一下几个问题需要搞清楚。
怎样创建 Promise 对象
用 Promise 对象创建 Promise 实例
1 | // 创建 Promise 对象 |
用 async 创建 Promise 实例
async 函数返回一个 Promise 实例,我们可以用来创建 Promise 实例。
1 | async function prm () { |
链式调用时参数是怎样传递的
then() 参数的传递
1 | // 创建 Promise 对象 |
执行上面的代码,我们发现,第1个 then() 的参数是 resolve() 的参数值,第2个 then() 及之后的 then() 的参数值都是其上一个 then() 的返回值。
catch() 参数的传递
catch() 参数的传递和 then() 不同,要把错误从 catch() 传给下一个 catch(),需要在 catch() 中抛出错误。
1 | Promise.resolve().then(() => { |
在 then() 中怎样传值给上级代码块
js Promise 是异步的,同一个 Promise 的 then() 方法是按代码顺序的一个 then 到下一个 than 的执行,但和than 外部的代码块是异步的。如果要把 then 代码块的值传给上层的代码块,回调是常用的方法,但如果上层代码块还需要返回异代码块中的值的时候,回调就做不到了。
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先等待,等到该处的异步操作完成,再接着执行函数体内后面的语句。加上 await 后,将返回回调函数的返回值。
1 | const prm = new Promise((resolve, reject) => { |
注意
1、await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。
1 | async function myFunction() { |
2、多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
1 | let foo = await getFoo(); |
上面代码中,getFoo 和 getBar 是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有 getFoo 完成以后,才会执行 getBar,完全可以让它们同时触发。
1 | let [foo, bar] = await Promise.all([getFoo(), getBar()]); |
3、await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。从 ES2022 开始允许 await 可以在顶层使用,不需要在 async 函数中。
参考: ECMAScript 6 入门
彻底搞清 JavaScript Promise
https://coderpan.com/front-end/javascript-promise-get-over.html