首先对于Promise不太熟悉的朋友建议可以先看一下我的这两篇关于Promise的文章
async-await和Promise的关系
async-await是promise和generator的语法糖。只是为了让我们书写代码时更加流畅,当然也增强了代码的可读性。简单来说:async-await 是建立在 promise机制之上的,并不能取代其地位。async和await最关键的用途是以同步的写法实现了异步调用。
基本语法
async function fn() {
let result = await Math.random();
console.log(result);// 0.10492893687819915
}
console.log(fn());// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}
上述代码就是async-await的基本使用形式。有两个陌生的关键字async、await,同时函数执行结果返回了一个promise对象,这样一看似乎并没有什么特别之处。
async
async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。
async function fn1() {
return 666;
}
fn1().then(val => {
console.log(val);// 666
});
若 async 定义的函数有返回值,return 666;相当于Promise.resolve(666),没有声明式的 return则相当于执行了Promise.resolve();
await
await 可以理解为是 async wait 的简写。await 必须出现在 async 函数内部,不能单独使用。
function badFn() {
await Math.random();
}
badFn();// Uncaught SyntaxError: await is only valid in async function
await 后面可以跟任何的JS 表达式。虽然说 await 可以跟很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的是 promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。
我们可以利用这一特性来实现一个sleep函数
async-await 实现 sleep()函数
function sleep(ms) {
return new Promise(
(resolve) => setTimeout(resolve, ms)
);
}
async function test() {
var temple = await sleep(1000);
console.log(1111)
return temple
}
test();
//延迟1000ms输出了1111
需求:此时我们有一个简单的需求,需要去依次去读取一些文件的内容。若用 ES5实现会有3层的回调,若用Promise 实现至少需要3个then。一个是代码横向发展,另一个是纵向发展。这里用async-await实现
const fs = require('fs')
function getFileByPath(fpath) {
return new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
if (err) return reject(err)
resolve(dataStr)
})
})
}
async function test() {
let res1 = await getFileByPath('./1.txt');
console.log(res1)
let res2 = await getFileByPath('./2.txt');
console.log(res2)
let res3 = await getFileByPath('./3.txt');
console.log(res3)
}
test()
运行,此时控制台依次输出文件一到三的内容。回看test函数,以同步的方式去书写异步逻辑,简直不要太爽。
不要滥用async-await
要选择合适的场景,还是那上面读取文件的例子来说,我还是需要读取三个文件,相互没有关联,只是需要三个文件全部读取完毕后提示即可。
此时你可能会说上面的可以实现需求啊。的确,不过此时就将异步的并发请求变成了阻塞式同步的操作了。严重影响效率,此时应该这样写。
async function test() {
let res1 = getFileByPath('./1.txt');
console.log(res1)
let res2 = getFileByPath('./2.txt');
console.log(res2)
let res3 = getFileByPath('./3.txt');
console.log(res3)
await Promise.all([res1, res2, res3]);
console.log('文件读取完成')
}
async-await只是promise的语法糖,还是需要用promise来实现。
await必须在async函数上下文中
async function forBugDemo() {
let arr = [1, 2, 3, 4, 5];
arr.forEach(item => {
await console.log(item);
});
}
forBugDemo();// Uncaught SyntaxError: await is only valid in async function
如上await并未在async函数上下文中故报错。。
正确写法如下
async function forDemo() {
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i ++) {
await console.log(arr[i]);
}
}
forDemo();