Promise、async/await使用场景

1.Prommise

1.Promis是做什么的?

  • 异步编程的解决方案,一种很常见的场景就是网络请求。
  • Promise 对象代表一个异步操作,有三种状态:
    • pending: 初始状态,不是成功或失败状态。
    • fulfilled: 意味着操作成功完成。
    • rejected: 意味着操作失败。

优点

  • 有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

缺点

  • 一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部
  • 当处于 Pending 状态时,无法得知目前进展到哪一个阶段

2.Promise.all

  • promise.all可以将多个promise实例包装成一个新的promise实例。同时,成功和失败的返回值是不同的。
    • 成功的时候返回一个数组
    • 失败时则返回最先被reject失败的状态的值。
  • 所有的请求都完成时,才返回一个数组。只要有一个失败了,就先返回这个失败的请求

需求:弹框弹出后的初始情况下,就让这个弹出框处于数据加载中的状态,当这两部分数据都从接口获取到的时候,才让这个数据加载中状态消失。让用户看到这两部分的数据。

这时我们就需要:两个异步接口请求任务都完成的时候做处理,所以此时,使用Promise.all方法,就可以轻松的实现

3.Promise.race方法

Promise.race赛跑机制,只认第一名,就是说promise.race([p1, p2, p3])里哪个结果捕获的快,就返回哪个结果
不管成功还是失败

Promise.race其实使用的并不多,如果真要使用。我们可以提出这样一个需求:

比如:点击按钮发请求,当后端的接口超过一定时间,假设超过三秒,没有返回结果,我们就提示用户请求超时

4.总结

  • Promise.all接收的是数组,得到的结果也是数组,并且一一对应,也可以理解为Promise.all照顾跑的最慢的,最慢的跑完才结束。
  • Promise.race接收的也是数组,不过,得到的却是数组中跑的最快的那个,当最快的一跑完就立马结束。

2.async与await

1.async做了什么?

  1. async会返回一个promise对象
  2. async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
async function fn1(){
    return 123
}

function fn2(){
    return 123
}

console.log(fn1()) //Promise {: 123}
console.log(fn2()) //123
1.1 注意
  • async表示函数内部有异步操作
  • 另外注意,一般 await 关键字要在 async 关键字函数的内部,await 写在外面会报错。

2.await 在等什么?

  • async函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值

  • 右侧如果是函数,那么函数的return值就是「表达式的结果」

    右侧如果是一个 ‘hello’ 或者什么值,那表达式的结果就是 ‘hello’

//Promise.then 成功情况 对应 await
async function test3 () {
  const p3 = Promise.resolve(3);
  p3.then(data => {
    console.log('data', data); //data 3
  })
  const data = await p3;
  console.log('data', data); //data3
}
test3(); //因此Promise.then 可以 await代替

async/await 的优势在于处理 then 链:

https://segmentfault.com/a/1190000007535316

3.await等到之后,做什么?

分两种情况:

1.不是promise对象

  • 如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果

2.是promise对象

  • 如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

3.今日头条面试题


    async function async1() {
        console.log( 'async1 start' )
        await async2()
        console.log( 'async1 end' )
    }
    
    async function async2() {
        console.log( 'async2' )
    }
    
    console.log( 'script start' )
    
    setTimeout( function () {
        console.log( 'setTimeout' )
    }, 0 )
    
    async1();
    
    new Promise( function ( resolve ) {
        console.log( 'promise1' )
        resolve();
    } ).then( function () {
        console.log( 'promise2' )
    } )
    
    console.log( 'script end' )

:答案是以浏览器的eventloop机制为准的,在node平台上运行会有差异

     script start
     async1 start
     async2
     promise1
     script end
     async1 end
     promise2
     setTimeout

4.首先看一下Event loop 宏任务 微任务

  • 执行顺序
    • 先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中
    • 遇到异步微任务则将异步微任务放入微任务队列中
    • 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行
    • 微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

5.分析面试题

1.直接打印同步代码 console.log(‘script start’)

首先是2个函数声明,虽然有async关键字,但不是调用我们就不看。然后首先是打印同步代码 console.log('script start')

2.将setTimeout放入宏任务队列

3.调用async1,打印 同步代码 console.log( ‘async1 start’ )

4.遇到await async2()

1.它先计算出右侧的结果,2.然后看到await后,中断async函数

- 先得到await右侧表达式的结果。执行async2(),打印同步代码console.log('async2'), 并且return Promise.resolve(undefined)
- await后,中断async函数,先执行async外的同步代码

目前就直接打印 console.log('async2')

被阻塞后,执行async之外的代码

5.执行new Promise(),Promise构造函数是直接调用的同步代码,所以 console.log( ‘promise1’ )

代码运行到promise.then()

代码运行到promise.then(),发现这个是微任务,所以暂时不打印,只是推入当前宏任务的微任务队列中。

6.打印同步代码console.log( ‘script end’ )

7.执行微任务打印console.log( ‘async1 end’ )

8.执行微任务打印promise2

9.执行宏任务console.log(‘setTimeout’)

你可能感兴趣的:(JavaScript,leetcode,算法,职场和发展)