1.什么是 async(其实就跟then方法是基本一致的)

async 顾名思义就是异步的意思,它是ES2017标准中引入的一种新函数,它是Generator函数的语法糖,它是作用是简化异步操作,使得异步操作更加简单

  • async函数的返回值为 promise 对象
  • promise 对象的结果由 async 函数执行的返回值决定
    //几乎跟then方法是一模一样
    async function main1(){
    //1. 如果返回值是一个非Promise类型的数据
    return 'hello!';
    }

    async function main2(){
    //2. 如果返回的是一个Promise对象(返回的是resolve类型)
    return new Promise((resolve, reject) => {
    resolve('OK');
    });
    }

    async function main3(){
    //3. 如果返回的是一个Promise对象(返回的是reject类型)
    return new Promise((resolve, reject) => {
    reject('Error');
    });
    }

    async function main4(){
    //4. 抛出异常
    throw "Oh NO";
    }
    console.log(main1());//Promise {<fulfilled>: 'hello!'}
    console.log(main2());//返回结果:状态为fulfilled的promise对象,返回值为OK
    console.log(main3());//返回结果:状态为rejected的promise对象,返回值为Oh No
    console.log(main4());//Promise {<rejected>: 'Oh NO'}

结果如下:

image

2.什么是 await ?

await顾名思义就是等待,它同样是ES2017中新引入的一种新表达式,用于嵌套async来使用,解决异步操作

  • await 右侧的表达式一般为 promise 对象, 但也可以是其它的值(数字,字符串,布尔类型等,运算也可以)
  • 如果表达式是 promise 对象, await 返回的是 promise 成功的值(切记是成功的值)
  • 如果表达式是其它值, 直接将此值作为 await 的返回值(即右侧是什么我就返回什么)

注意:

  • 1.await 必须写在 async 函数中, 但 async 函数中可以没有 await(就好比单相思)
  • 2.如果 await 的 promise 失败了, 就会抛出异常, 则需要通过 try…catch 捕获处理

普及一下try-catch语法:

  • try catch语句是JavaScript中一种处理异常的标准方式
    try {
    //可能会导致错误的代码
    } catch (e(error的缩写)) {
    //在错误发生时该如何进行处理
    }

await 的使用demo

async function main1(){
let p = new Promise((resolve, reject) => {
resolve('OK');
})
//1. 右侧为promise的情况 await会返回Promise对象为成功状态时的值
let res = await p;
console.log(res);
}

async function main2(){
let p = new Promise((resolve, reject) => {
resolve('OK');
})
//2. 右侧为其他类型的数据,直接返回右侧变量值(即右侧是什么,我就给你返回什么)
// 一般这种情况很少见,多数情况是 Promise对象
let res2 = await 20;
console.log(res2);
}

async function main3(){
let p = new Promise((resolve, reject) => {
reject('Eorr');
})
//3. 如果promise是失败的状态就会抛出一个错误,这时我们就需要用try-catch来捕获处理这个错误
try{
let res3 = await p;
}catch(e){
// 在这里获取失败的结果
console.log(e);
}
}

main1();//结果为:OK
main2();//结果为:20
main3();//结果为:Eorr

结果如下:

image

3.util.promisify 函数用法的讲解

什么是 util.promisify?

  • util.promisify是在node.js 8.x版本中新增的一个工具,用于将老式的Error first callback转换为Promise对象,让老项目改造变得更为轻松。
  • 首先要解释一下这种工具大致的实现思路,因为在Node中异步回调有一个约定:Error first,也就是说回调函数中的第一个参数一定要是Error对象,其余参数才是正确时的数据。

作用:

  • 传入一个错误优先的回调风格的函数(即形参要求错误优先(err,value)),返回一个promise版本
    //引入 util 模块
    const util = require('util');
    //引入 fs 模块
    const fs = require('fs');
    //返回一个新的函数
    // fs.readFile就是一个错误优先的函数方法(readFile('path',(err,data)=>{}))
    let mineReadFile = util.promisify(fs.readFile);

    // 直接读取Promise对象里面的value值
    mineReadFile('./resource/content.txt').then(value=>{
    console.log(value.toString());//转换buffer
    });

结果如下:

image

async和await两者的结合使用大大方便了我们的开发(案例)

  • 案例要求:读取resolve文件夹下面的三个文件:1.html 2.html和3.html

第一种方式:使用回调函数

//回调函数的方式(存在回调地狱,存在错误要每一层去做if-else判断,非常麻烦)
// 导入模块
const fs = require('fs');
fs.readFile('./resource/1.html', (err, data1) => {
if(err) throw err;
fs.readFile('./resource/2.html', (err, data2) => {
if(err) throw err;
fs.readFile('./resource/3.html', (err, data3) => {
if(err) throw err;
console.log(data1 + data2 + data3);
});
});
});

第二种方式:async嵌套await

//没有回调地狱,并且整体简洁高效
// 导入模块
const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisify(fs.readFile);

async function main(){
try{
//读取第文件的内容
let data1 = await mineReadFile('./resource/1.html');
let data2 = await mineReadFile('./resource/2.html');
let data3 = await mineReadFile('./resource/3.html');
// 没有错误则输出,有错误则抛出错误让下层的catch捕获
console.log(data1 + data2 + data3);
}catch(e){
// 输出错误信息
console.log(e);
}
}

main();

结果如下(两者均一致):

image

案例展示:

  • 要求:使用async/await来实现输出1 -> 2 -> 3,但是2要套一个延时函数(200ms),结果要输出1 -> 2 -> 3

代码展示:

  • 直接使用await限制异步操作:
async function test(){
await console.log('1');
await setTimeout(()=>{console.log('2');},20)
await console.log('3');
}
test()// 结果输出: 1 -> 3 -> 2
  • 结果展示:
    image

  • 由此可见:结果不尽如人意,那是因为await只能控制promise实例对象,因此要想实现使用await控制异步,就需要在给异步操作外面添加一层promise

代码如下:

async function test(){
await console.log('1');
/* 给延时函数异步操作为套上一层promise */
await new Promise((resolve)=>{
setTimeout(()=>{console.log('2');resolve()},20)
})
await console.log('3');
}
test() // 结果输出: 1 -> 2 -> 3
//说明await只能控制promise实例对象,因此要想实现使用await控制异步,就需要在给异步操作外面添加一层promise
  • 结果展示:
    image