2021.03.04 更新
2021.03.04
MDN好好看看:async函数
串行并行比较
show me the code.
// Promise写法let p = new Promise((resolve) => {setTimeout(() => {resolve("oppos");}, 2000);});p.then((result) => {console.log(result);});// async await写法function resolveAfter2Seconds() {return new Promise((resolve) => {setTimeout(() => {resolve("oppos");}, 2000);});}async function asyncCall() {const result = await resolveAfter2Seconds();console.log(result);}
从上面代码看出,在await表达式下面的代码可以被认为是存在于链式调用的then回调中,多个await表达式都将加入链式调用的then回调中,返回值将作为最后一个then回调的返回值。
串行、并行关系也可与Promise写法进行比较,async/await写法更简洁:串并行写法比较.js
async函数一定会返回一个promise对象。
async function foo() {return 1}// 等价于async function foo() {return Promise.resolve(1);}
一个简单的语法比较,并判断输出顺序:
async function sums(a, b) {console.log("a,b");console.log(await 22);// 等价于new Promise((resolve) => {resolve(33);}).then((res) => {console.log(res);});// 等价于Promise.resolve(55).then((res) => {console.log(res);});return a + b;}console.log("object", "start");sums(5, 6).then((res) => {console.log(res);});console.log("object", "end");
2020.08.26 版本 — 主要摘抄自阮一峰的文档,自己也看不懂…
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。是 Generator 函数的语法糖。
2020.08.26
基本用法
在一个函数前添加async,这个函数就会返回Promsie对象。当该函数执行时,遇到await就会先返回,等到异步完成,再接着执行函数体后面的语句。
async函数返回一个 Promise 对象,内部return语句返回的值,会成为then方法回调函数的参数:
async function f() {return 'hello world';}f().then(v => console.log(v))// "hello world"
async函数内部抛出错误会被catch方法接收到:
async function f() {throw new Error('出错了');}f().then(v => console.log(v),e => console.log(e))// Error: 出错了// 或这样写f().catch(e=>console.log(e))
状态变化
async的状态必须等到内部所有await命令后面的Promise对象都执行完才会发生状态改变,除非遇到return或抛出错误。
async function getTitle(url) { // 执行顺序let response = await fetch(url); // 1let html = await response.text(); // 2return html.match(/<title>([\s\S]+)<\/title>/i)[1]; // 3}getTitle('https://tc39.github.io/ecma262/').then(console.log)
await命令
await后面的参数:
- 若为Promise对象,则返回该对象的结果;
- 若为其它,直接返回对应的值;
- 若对象包含then方法,将其等同于Promise对象;
await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。
错误处理
async函数内部抛出的错误,可以被catch方法捕获到:
async function f() {await Promise.reject("出错了");}f.catch(e=console.log(e));
或者放于try…catch结构里:
async function f() {try{await Promise.reject("出错了1");await Promise.reject("出错了2");} catch(e){console.log(e)}}
注意:任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。
async function f() {await Promise.reject('出错了');await Promise.resolve('hello world'); // 不会执行}
若希望前面的await失败不影响后面的异步操作,有2种方法:
(1)第一个await放在try…catch结构中:
async function f() {try {await Promise.reject('出错了');} catch(e) {console.log(e)}await Promise.resolve('hello world');}
(2)第一个await后面的Promise对象跟一个catch方法:
async function f() {await Promise.reject('出错了').catch(e => console.log(e));await Promise.resolve('hello world');}
串行与并行
串行异步:
// 只有getFoo完成了getBar才开始执行let foo = await getFoo();let bar = await getBar();
并行异步:
// 写法一let [foo, bar] = await Promise.all([getFoo(), getBar()]);// 写法二let fooPromise = getFoo();let barPromise = getBar();let foo = await fooPromise;let bar = await barPromise;// 同时触发,可以缩短程序执行时间
若两个异步操作互不依赖,则最好使用并行关系来缩短时间。
借助async/await,语义比Promise要简洁、清晰很多。
