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); // 1
let html = await response.text(); // 2
return 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要简洁、清晰很多。