zoukankan      html  css  js  c++  java
  • Promise结合setTimeout--promise练习题(2)

    Promise结合setTimeout

    题目1

    console.log('start')
    setTimeout(() => {
      console.log('time')
    })
    Promise.resolve().then(() => {
      console.log('resolve')
    })
    console.log('end')`
    

    输出:

    start
    end
    resolve
    time
    

    分析:

    1. 执行同步代码:
      • 打印start
      • 设置计时器(setTimeout),回调函数进入宏任务队列
      • 执行Promise.resolve.then(),回调函数是异步函数,进入微任务队列
      • 打印end
    2. 检查微任务队列,将其中任务放入执行栈执行——console.log('resolve');,队列空
    3. 检查宏任务队列,将其中任务放入执行栈执行—— console.log('time')

    同-->微-->宏

    题目2

    const promise = new Promise((resolve, reject) => {
      console.log(1);
      setTimeout(() => {
        console.log("timerStart");
        resolve("success");
        console.log("timerEnd");
      }, 0);
      console.log(2);
    });
    promise.then((res) => {
      console.log(res);
    });
    console.log(4);
    

    输出:

    1
    2
    4
    timeStart
    timeEnd
    success
    

    分析:

    1. 执行同步代码:
      • 给promise赋值
      • 打印1
      • 设置计时器,回调函数是异步函数,进入宏任务队列
      • 打印2
      • 给promise的解决处理函数赋值(resolve指向一个函数),但因为promise尚未调用resolve,所以该回调函数尚未进入任务队列
      • 打印4
    2. 检查微任务队列,为空
    3. 检查宏任务队列,依次执行
    console.log("timerStart");  
    resolve("success");
    console.log("timerEnd");
    

    因为resolve是异步函数,会被放入微任务队列,当宏任务队列所有能执行的任务都取出后,开始新的循环
    3. 执行栈为空,检查微任务队列,将微任务队列中的resolve放入执行栈执行,于是打印success

    箭头函数能够保留它创建时的作用域,调用该作用域中的变量和函数,所以setTimeout改变执行流后,仍能调用resolve。

    题目3

    (1)

    setTimeout(() => {
      console.log('timer1');
      setTimeout(() => {
        console.log('timer3')
      }, 0)
    }, 0)
    setTimeout(() => {
      console.log('timer2')
    }, 0)
    console.log('start')
    

    输出:

    start
    timer1
    timer2
    timer3
    

    (2)

    setTimeout(() => {
      console.log('timer1');
      Promise.resolve().then(() => {
        console.log('promise')
      })
    }, 0)
    setTimeout(() => {
      console.log('timer2')
    }, 0)
    console.log('start')
    

    输出:

    start
    timer1
    promise
    timer2
    

    分析:

    Promise.then是微任务,它会被加入到本轮中的微任务列表,而定时器timer3是宏任务,它会被加入到下一轮的宏任务中。
    每次执行完一个宏任务,主线程都会去检查一下微任务队列有没有任务,如果有就立即加入执行栈执行,直至微任务队列清空,再去执行下一个宏任务。

    题目3

    Promise.resolve().then(() => {
      console.log('promise1');
      const timer2 = setTimeout(() => {
        console.log('timer2')
      }, 0)
    });
    const timer1 = setTimeout(() => {
      console.log('timer1')
      Promise.resolve().then(() => {
        console.log('promise2')
      })
    }, 0)
    console.log('start');
    

    输出:

    start
    promise1
    timer1
    promise2
    timer2
    

    分析:

    1. 执行同步代码:
      • Promise.resolve.then()给resolve赋予一个箭头函数。该回调加入本轮微任务队列中,其中的定时器timer2将加入次轮宏任务队列
      • 给timer1设置一个定时器,回调函数加入本轮宏任务队列,promise.then加入次轮微任务队列
      • 打印start
    2. 检查微任务队列:
      • 第一个Promise的解决处理函数被放入执行栈
      • 打印promise1
      • 为timer2添加定时器,回调函数加入本轮宏任务队列(已经是第二轮了)
      • 执行栈为空
    3. 检查宏任务队列
      • timer1定时器的回调函数转移到执行栈上
      • 打印timer1
      • 将第二个Promise的解决处理函数加入本轮微任务队列(已经是第二轮了)
      • 执行栈为空
    4. 检查微任务队列
      • 一旦微任务队列不为空就需要从宏任务队列离开去执行微任务
      • 打印promise2
    5. 检查宏任务队列
      • 打印timer2

    image

    题目4

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        //console.log("success setTimeout");
        resolve('success')
      }, 1000)
    })
    const promise2 = promise1.then(() => {
      throw new Error('error!!!')
    })
    console.log('promise1', promise1)
    console.log('promise2', promise2)
    setTimeout(() => {
      console.log('promise1', promise1)
      console.log('promise2', promise2)
    }, 2000)
    

    输出:

    promise1 Promise{<pending>}
    promise2 Promise{<pending>}
    //success setTimeout
    Uncaught (in promise) Error: error!!!
    promise1 Promise{<fulifilled> success}
    promise2 Promise{<rejected> Error: error!!!}
    

    分析:

    1. 执行同步代码
      • 给promise1赋值
      • 设置一个定时器,1秒后回调函数进入本轮宏任务队列
      • 给promise2赋值,then的回调函数加入微任务队列
      • 打印"promise1"和promise1的状态,目前promise1的状态依然是pending
      • 打印"promise2"和promise2的状态,目前promise2的状态依然是pending
      • 设置定时器,2秒后回调函数加入宏任务队列
    2. 检查微任务队列,空
    3. 检查宏任务队列,空
    4. 1秒,微任务队列依然为空
    5. 1秒,定时器触发,执行resolve("success");
    6. promise2的处理函数被放入微任务队列
    7. 将微任务队列的回调函数放入执行栈处理——throw new Error("error!!!"),抛出错误
    8. 2秒,微任务队列为空
    9. 2秒,将宏任务调入执行栈执行
      console.log('promise1', promise1)
      console.log('promise2', promise2)
    

    此时promise1-->fulfilled,promise2-->rejected

    可以提前给期约的处理函数赋值,但只有当状态转变时,回调函数才会进入微任务队列
    如果先转状态,那么给相应处理函数赋值时,回调函数就会进入微任务队列

    题目5

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("success");
        console.log("timer1");
      }, 1000);
      console.log("promise1里的内容");
    });
    const promise2 = promise1.then(() => {
      throw new Error("error!!!");
    });
    console.log("promise1", promise1);
    console.log("promise2", promise2);
    setTimeout(() => {
      console.log("timer2");
      console.log("promise1", promise1);
      console.log("promise2", promise2);
    }, 2000);
    

    输出:

    promise1里的内容
    promise1 Promise{<pending>}
    promise2 Promise{<pending>}
    timer1
    Uncaught (in promise) Error: error!!!
    timer2
    promise1 Promise{<fulfilled> success}
    promise2 Promise{<rejected> Error error!!!}
    

    分析:
    与上一题类似

    感谢阅读。

    百炼成钢!!!

    参考:

    【建议星星】要就来45道Promise面试题一次爽到底(1.1w字用心整理)
    《JavaScript高级程序设计》(第四版)

  • 相关阅读:
    ToDesk 远程连接软件 连接远程电脑后黑屏
    Kentico updateall
    Stylesheet not loaded because of MIME-type
    Linux tail 命令作用及其常用用法
    浅析Linux中stty命令的作用、常用用法及案例使用
    【MySQL】修改表的存储引擎
    【MySQL】查看MySQL的默认存储引擎(Win环境)
    【Swing/STS】在Spring Tool Suite中制作可执行jar
    [Swing]我的作品 图片幻灯式浏览软件PicturesShow 献给广大美图爱好者的福音
    【Java Swing】如何给Jframe添加键盘和鼠标事件处理
  • 原文地址:https://www.cnblogs.com/liulangbxc/p/15338736.html
Copyright © 2011-2022 走看看