string

1.1 async基本使用

返回promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getData (ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

async function foo(value, ms) {
// 等到await 有结果后才会执行后面的代码。
await getData(ms);
console.log(value);
return {
a: 3
}
}
// 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
foo('hello world', 1000).then((res) => {
console.log(res)
})

1.2 async声明方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}

async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

// 箭头函数
const foo = async () => {};

1.3 await 命令

正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。

1
2
3
4
5
6
async function f() {
// 等同于 return 123;
return await 123;
}

f().then(v => console.log(v))

await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

1
2
3
4
5
6
7
async function f() {
await Promise.reject('出错了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))

不存在块作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

async function foo(value, ms) {
if (true) {
if (true) {
await timeout(ms);
}
}
// console.log依然会被阻塞
console.log(value);
}

foo('await and await', 1000);

注意

await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function foo() {
try {
await someFoo();
} catch (err) {
console.log(err);
}
}

// 另一种写法

async function foo() {
await someFoo()
.catch(function (err) {
console.log(err);
});
}

多请求并发

1
2
3
4
5
6
7
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));

let results = await Promise.all(promises);
console.log(results);
}

async 原理

1
2
3
4
5
6
7
8
9
10
11
async function fn(args) {
// ...
}

// 等同于, spawn是自动执行器

function fn(args) {
return spawn(function* () {
// ...
});
}

自执行器材

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}

async 带来的思考

参照代码

1
2
3
4
5
6
7
8
(async () => {
const gOne = await getOne(); // async
const gTow = await getTwo(); // async
const sOne = setOne(); // sync
const sTwo = setTwo(); // sync
await dealOne(gOne); // async
await dealTwo(gTow); // async
})();

假如 gOne 与 gTow 之间没有依赖,await 会阻塞 getTwo 函数执行(使其额外等待getOne请求的时间),但其实 getOne 和 getTwo 两个请求接口应该 “并行” 执行才更合理

合理做法:先同时执行函数,再 await 返回值

1
2
3
4
5
6
(async () => {
const gOne = getOne();
const gTow = getTwo();
await gOne;
await gTow;
})();

使用 Promise.all 更香

1
2
3
(async () => {
const result = await Promise.all([getOne(), getTwo()])
})();

优点

  • 语法简洁清晰,节省了很多不必要的匿名函数

  • 直接使用 try…catch… 进行异常处理

  • 添加条件判断更符合直觉

  • 减少不必要的中间变量

  • 更清晰明确的错误堆栈

  • 调试时可以轻松给每个异步调用加断点

返回
顶部