ES6 Promise和 async异步函数用法流程及原理小结(vue必用!面试必问!)

173 阅读5分钟

Promise介绍

ES6教程传送门:es6.ruanyifeng.com/#docs/promi…

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise`对象提供统一的接口,使得控制异步操作更加容易。

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。

1.什么是Promise

Promise是构造函数, 用于创建promise实例对象
  作用 :  解决回调地狱
    回调地狱 :  异步回调,层层嵌套
    promise场景:  让异步代码按照同步的顺序执行,并且避免回调嵌套
   

代码演示地狱回调

//需求: 依次读取文件a , b , c

const fs = require('fs')

/* 如何让异步代码按照顺序执行  :  异步嵌套 */
//读取文件a
fs.readFile(`${__dirname}/data/a.txt`, 'utf-8', (err, data) => {
    if (err) {
        throw err
    } else {
        console.log(data)
        //读取文件b
        fs.readFile(`${__dirname}/data/b.txt`, 'utf-8', (err, data) => {
            if (err) {
                throw err
            } else {
                console.log(data)
                //读取文件c
                fs.readFile(`${__dirname}/data/c.txt`, 'utf-8', (err, data) => {
                    if (err) {
                        throw err
                    } else {
                        console.log(data)
                        //读取文件d
                        fs.readFile(`${__dirname}/data/d.txt`, 'utf-8', (err, data) => {
                            if (err) {
                                throw err
                            } else {
                                console.log(data)
                            }
                        })
                    }
                })
            }
        })
    }
})

2. Promise使用流程: 两个步骤

     2.1 创建Promise实例对象 :   
    let p = new Promise((resolve,reject)=>{
        //异步代码
        if( 成功 ){ 
            //调用resolve() 就会执行then第一个回调
            resolve(数据) 
        }else{ 
            //reject() 就会执行then第二个回调
            reject(错误信息)
        }
    })
   2.2 调用promise实例的then方法 :
    p.then( res=>{
        //成功
    } , err=>{
        //失败
    })

3. Promise原理 : Promise本质是一个容器

3.1 Promise有三种工作状态

    进行中 pending
    已成功 fulfilled
    已失败 rejected

3.2 Promise状态切换只有两种情况

pending(进行中)变成fulfilled(已成功)
    从pending(进行中)变成rejected(已失败)

3.3 promise创建的时候里面的代码会立即执行

    (1)不要在promise里面去处理异步结果
    (2)而是执行promise的resolve与reject方法

3.4 promise解决回调地狱:

   在上一个promise对象的then方法中返回 下一个promise对象
    p1.then(res=>{ return p2 })
    .then( res=>{ } )

总结 : promise本身无法控制异步顺序(异步无序的),只是控制 异步结果的 顺序

4.promise其他用法(了解)

catch : 捕捉promise对象的异常错误信息

image.png

all : 将多个promise放入数组中合并成一个promise, 只有数组中所有的promise执行完毕才会执行then

image.png 代码介绍

let p1 = createPromise('a')
let p2 = createPromise('b')
let p3 = createPromise('c')

// Promise.all( [p1,p2,p3] ) : 多个promise对象合并成一个
let pAll = Promise.all( [p1,p2,p3] )

//(2)调用then方法
pAll.then(res=>{
    //上面所有的promise全部都执行完毕,才会执行then
    console.log(res)
}).catch(err=>{
    console.log(err)
})

race :将多个promise放入数组中合并成一个promise, 只要数组中任意promise执行完毕就会执行then

image.png

async异步函数

1. async异步函数 : 相当于 promise 的更高级写法
   async关键字:  修饰 异步函数,让函数支持await
   await关键字:  阻塞当前函数执行,等待promise的resolve()结果

2. async使用两个流程
   2.1 使用async关键字修饰函数:   async function 函数名(){}
   2.2async函数中用await来执行promise : let res =  await promise实例对象

异步函数使用流程

(1)使用async关键字修饰函数 : 让这个函数内部可以识别await关键字
(2)使用await关键字调用 promise异步 , await的结果就是 promise内部的resolve()结果

代码演示

async function fn() {

    //res1就是await后面那个promise的then里面的res
    let res1 = await readPromise('a')
    console.log(res1)

    let res2 = await readPromise('b')
    console.log(res2)

    let res3 = await readPromise('c')
    console.log(res3)

}

fn()