ES6异步

63 阅读4分钟

一、Promise篇

1.1 Promise基本用法

    // getCaseId 函数new Promise构造函数,生成了一个Promise实例。
    // new Promise() 是创建Promise实例的方法。
    function getCaseId() {
        return new Promise((resolve, reject) => {
            const success = true
            setTimeout(function () {
                if (success) {
                    resolve('成功') // pending -> resolved 一旦改变,状态就凝固了,不会再变了。
                }
                reject('失败') // pending -> rejected
            },3000)
        })
    }
    // Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
    getCaseId()
        .then(res => {
        		console.log(res) // res是resolve() 里的值
        }) // then () 返回的还是个Promise实例
        .catch(err => { // err 是rejected() 里的值
        		console.log(err) 
    		})
  • Promise对象是一个构造函数,用来生成Promise实例。
  • Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。

resolve: pending->resolved 状态。

rejected: pending->rejected 状态。

  • Promise.prototype.then() : 执行完resolve(),状态变为resolved状态时去调用。then()返回的还是个Promise的实例。
  • Promise.prototype.catch() :执行完rejected(),状态变为rejected状态时去调用,捕获错误。

Promise链式调用

return checkAllowApplyClaim().then(getOrderBrief).then(getMaterialGroupList);

getOrderBrief是作为回调函数进去的,和Promise.then(res => {})中的res=> {} 是一样的,会自己执行这个回调。

1.2 Promise静态方法

1.3 Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。成了一个Promise实例。

const p = Promise.all([p1, p2, p3]);

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值(resolve()返回的值)组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

适合 希望一个失败就失败的场景

promise.all [ 
  let a = new Promise();  // a 和 b都是Promise的实例
  let b = new Promise(); 
]

注意:2个请求同时发出,a和b 不能确定返回顺序。 即a是否返回对b没有影响。

1.4 Promise.race()

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.allSettled()

只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束.该方法由 ES2020 引入。

二、async篇

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

2.1 定义

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

  • 同步方式写异步
  • 解决Promise回调地狱(有依赖关系那种)的问题。
async function main() {
 try {
   const val1 = await firstStep(); // await后面一个promise对象,val1的值是firstStep里reslove()的值
   const val2 = await secondStep(val1);
   const val3 = await thirdStep(val1, val2);
   return [...val1, ...val2, ...val3]
 }
 catch (err) { // err 是rejected的值
   console.error(err);
 }
}

main().then(res => {
        console.log('111')
    }).catch(err => {
        console.log(err)
    }) // catch 不会走了,已经捕获了。所以没必要写。
改为:main();

async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。

也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。

async函数内部return语句返回的值,会成为then方法回调函数的参数.

2.2 await

  1. 正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
  2. await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到
  3. await 之间有继发关系,val1 走了才有val2 ,即同步方式写异步。缺点时:比较耗时。

所以,没有依赖关系的,完全可以让它们同时触发。

 let [val1, val2] = await Promise.all([firstStep(), secondStep()]);

2.3 try {} catch(e) {}

请求失败后的处理, 可以使用try-catch来进行

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

firstStep(),返回rejected状态时,就走catch了捕获了错误,后面的secondStep thirdStep 都不会执行。

  1. await 之间有继发关系,val1 走了才有val2 ,即同步方式写异步。
    缺点时:比较耗时。所以,没有依赖关系的,完全可以让它们同时触发。多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
let foo = await getFoo();
let bar = await getBar();

上面代码中,getFoo和getBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发。

let [foo, bar] = await Promise.all([getFoo(), getBar()]);

三、参考 zhuanlan.zhihu.com/p/112081953