美文网首页ECMAScript6面试知识点Promise面试知识点
Promise从入门到拿Offer之async 与 await、

Promise从入门到拿Offer之async 与 await、

作者: 团子哒哒 | 来源:发表于2021-01-20 11:00 被阅读0次

    1、async函数

    函数的返回值为promise对象,promise对象的结果由async函数执行的返回值决定。如果任何一个await语句后面的 Promise 对象变为reject状态或遇到return,那么整个async函数都会中断执行。

    await 在等待 Promise 对象时会导致 async function 暂停执行, 一直到 Promise 对象决议之后才会 async function 继续执行。

    2、await表达式

    await右侧的表达式一般为promise对象,但也可以是其他的值;

    如果表达式是promise对象,await返回的是promise成功的值;如果表达式是其他值,直接就将此值作为await的返回值。

    注意:await必须写在async函数中,但async函数中可以没有await;如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理。

    常见的场景:

    场景1. 一个请求接着一个请求;

    场景2.并发请求;

    场景3.错误处理;

    场景4. 超时处理;

    场景5. 并发限制。

    3、宏队列与微队列

    JS引擎执行图

    JS中包含两个不同的队列用来存储待执行的回调函数,即宏队列和微队列。

    宏队列用来保存待执行的宏任务。如定时器回调、DOM事件回调、Ajax回调。

    微队列用来保存待执行的微任务,比如promise回调、mutationObserver()的回调。

    JS引擎执行顺序:

    1)首先执行初始化的同步代码块,遇到回调函数,需保存到对应的队列中。

    2)执行微队列中的微任务。在此也可能继续存在不同的回调函数,需继续存入相应的队列。

    3)每次准备执行取出第一个宏任务执行前,检查微队列是否存在微任务待执行,如果存在,则先执行微任务。

    示例分析:
    ```

    1 console.log("AAAA");

    2 setTimeout(() => console.log("BBBB"), 1000);

    3 const start = new Date();

    4 while (new Date() - start < 3000) {}

    5 console.log("CCCC");

    6 setTimeout(() => console.log("DDDD"), 0);

    7 new Promise((resolve, reject) => {

    8  console.log("EEEE");

    9  foo.bar(100);

    10 })

    11 .then(() => console.log("FFFF"))

    12 .then(() => console.log("GGGG"))

    13 .catch(() => console.log("HHHH"));

    14 console.log("IIII");

    ```

    一开始代码执行,输出`AAAA`. 1

    第二行代码开启一个计时器t1(一个称呼),这是一个异步任务且是宏任务,需要等到1秒后提交。

    第四行是个while语句,需要等待3秒后才能执行下面的代码,这里有个问题,就是3秒后上一个计时器t1的提交时间已经过了,但是线程上的任务还没有执行结束,所以暂时不能打印结果,所以它排在宏任务的最前面了。

    第五行又输出`CCCC`

    第六行又开启一个计时器t2(称呼),它提交的时间是0秒(其实每个浏览器器有默认最小时间的,暂时忽略),但是之前的t1任务还没有执行,还在等待,所以t2就排在t1的后面。(t2排在t1后面的原因是while造成的)都还需要等待,因为线程上的任务还没执行完毕。

    第七行`new Promise`将执行promise函数,它参数是一个回调函数,这个回调函数内的代码是同步的,它的异步核心在于resolve和reject,同时这个异步任务在任务队列中属于微任务,是优先于宏任务执行的,(不管宏任务有多急,反正我是VIP)。所以先直接打印输出同步代码`EEEE`。第九行中的代码是个不存在的对象,这个错误要抛给reject这个状态,也就是catch去处理,但是它是异步的且是微任务,只有等到线程上的任务执行完毕,立马执行它,不管宏任务(计时器,ajax等)等待多久了。

    第十四行,这是线程上的最后一个任务,打印输出 `IIII`

    我们先找出线程上的同步代码,将结果依次排列出来:AAAA  CCCC  EEEE IIII

    然后我们再找出所有异步任务中的微任务 把结果打印出来  HHHH

    最后我们再找出异步中的所有宏任务,这里t1排在前面t2排在后面(这个原因是while造成的),输出结果顺序是 BBBB DDDD

    所以综上 结果是  AAAA  CCCC  EEEE  IIII  HHHH BBBB DDDD

    4、JS的异步处理函数有哪些

    1)Promise 对象

    Promise是异步编程的一种解决方案,

    优点: 相比传统回调函数和事件更加合理和优雅,Promise是链式编程(后面会详细讲述),有效的解决了令人头痛的回调地狱问题,Promise的结果有成功和失败两种状态,只有异步操作的结果,可以决定当前是哪一种状态,外界的任何操作都无法改变这个状态。

    2)Generator 函数

     Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

    特征:一是,function关键字与函数名之间有一个星号;

    二是,函数体内部使用yield表达式,定义不同的内部状态;

    三是,通过next方法获取每段状态的返回结果。

    上面分成4次执行了Gennrator函数,第一次,获取第一个yield函数的返回结果并暂停,done:false,代表函数内的状态还没有执行结束;第二次,同理;第三次,获取return的返回结果,done:true表示函数内的状态已经执行完毕;第四次,函数内已经没有可以执行的状态,所有返回undfined,同时告诉函数内的状态已经执行完毕;如果函数内没有return,在第三次时返回undfined,done:true表示函数内的状态已经执行完毕。

    3)async 函数

    async 函数是在ES2017 标准中引入的,async使得异步操作变得更加方便,其实他就是Generator 函数的语法糖。

     相比Generator函数,async函数有如下四点改进:

    a、内置执行器: Generator 函数的执行必须靠next()进行每一次的模块执行,async自带执行器,只需要和普通函数一样调用即可执行

    b、更好的语义:async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

    c、返回值是Promise: async函数的返回值是 Promise 对象,可以用then方法指定下一步的操作;而且async函数完全可以看做多个异步函数的操作,包装成的一个 Promise对象,而await命令就是内部then命令的语法糖,即Promise.all()的用法

    4)回调函数   

    5)事件监听

    采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

    6)发布订阅模式

    存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)

    相关文章

      网友评论

        本文标题:Promise从入门到拿Offer之async 与 await、

        本文链接:https://www.haomeiwen.com/subject/kcnhzktx.html