美文网首页
promise 练习题(二)

promise 练习题(二)

作者: 老衲不生气 | 来源:发表于2020-06-06 17:51 被阅读0次

    promise 结合 setTimeout

    需要理解的知识点:
    event loop执行顺序

    • 一开始整个脚本作为一个宏任务执行
    • 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
    • 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
    • 执行浏览器UI线程的渲染工作
    • 检查是否有Web Worker任务,有则执行
    • 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

    微任务包括:MutationObserver、Promise.then()或catch()、Promise为基础开发的其它技术,比如fetch API、V8的垃圾回收过程、Node独有的process.nextTick。

    宏任务包括:script 、setTimeout、setInterval 、setImmediate 、I/O 、UI rendering。
    ————————————————————————————————————————

    //1、
    console.log('start')
    setTimeout(() => {
      console.log('time')
    })
    Promise.resolve().then(() => {
      console.log('resolve')
    })
    console.log('end')
    
    分析过程
    • 刚开始整个脚本作为一个宏任务来执行,对于同步代码直接压入执行栈进行执行,因此先打印出start和end。
    • setTimout作为一个宏任务被放入宏任务队列(下一个)
    • Promise.then作为一个微任务被放入微任务队列
    • 本次宏任务执行完,检查微任务,发现Promise.then,执行它
    • 接下来进入下一个宏任务,发现setTimeout,执行。
    执行结果

    'start'
    'end'
    'resolve'
    '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);
    
    分析过程
    • 从上至下,先遇到new Promise,执行该构造函数中的代码1
    • 然后碰到了定时器,将这个定时器中的函数放到下一个宏任务的延迟队列中等待执行
    • 执行同步代码2
    • 跳出promise函数,遇到promise.then,但其状态还是为pending,这里理解为先不执行
    • 执行同步代码4
    • 一轮循环过后,进入第二次宏任务,发现延迟队列中有setTimeout定时器,执行它
    • 首先执行timerStart,然后遇到了resolve,将promise的状态改为resolved且保存结果并将之前的promise.then推入微任务队列
    • 继续执行同步代码timerEnd
    • 宏任务全部执行完毕,查找微任务队列,发现promise.then这个微任务,执行它。
    执行结果

    1
    2
    4
    "timerStart"
    "timerEnd"
    "success"

    ————————————————————————————————————————

    //3、
    //(1):
    setTimeout(() => {
      console.log('timer1');
      setTimeout(() => {
        console.log('timer3')
      }, 0)
    }, 0)
    setTimeout(() => {
      console.log('timer2')
    }, 0)
    console.log('start')
    //(2):
    setTimeout(() => {
      console.log('timer1');
      Promise.resolve().then(() => {
        console.log('promise')
      })
    }, 0)
    setTimeout(() => {
      console.log('timer2')
    }, 0)
    console.log('start')
    
    分析过程
    • 这两个例子,看着好像只是把第一个定时器中的内容换了一下而已。一个是为定时器timer3,一个是为Promise.then。但是如果是定时器timer3的话,它会在timer2后执行,而Promise.then却是在timer2之前执行。
      你可以这样理解,Promise.then是微任务,它会被加入到本轮中的微任务列表,而定时器timer3是宏任务,它会被加入到下一轮的宏任务中。
    执行结果

    (1)'start'
    'timer1'
    'timer2'
    'timer3'
    (2)'start'
    'timer1'
    'promise'
    'timer2'

    ————————————————————————————————————————

    //4、
    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');
    
    分析过程
    • 刚开始整个脚本作为第一次宏任务来执行,我们将它标记为宏1,从上至下执行
    • 遇到Promise.resolve().then这个微任务,将then中的内容加入第一次的微任务队列标记为微1
    • 遇到定时器timer1,将它加入下一次宏任务的延迟列表,标记为宏2,等待执行(先不管里面是什么内容)
    • 执行宏1中的同步代码start
    • 第一次宏任务(宏1)执行完毕,检查第一次的微任务队列(微1),发现有一个promise.then这个微任务需要执行
    • 执行打印出微1中同步代码promise1,然后发现定时器timer2,将它加入宏2的后面,标记为宏3
    • 第一次微任务队列(微1)执行完毕,执行第二次宏任务(宏2),首先执行同步代码timer1
    • 然后遇到了promise2这个微任务,将它加入此次循环的微任务队列,标记为微2
    • 宏2中没有同步代码可执行了,查找本次循环的微任务队列(微2),发现了promise2,执行它
      第二轮执行完毕,执行宏3,打印出timer2
    执行结果

    'start'
    'promise1'
    'timer1'
    'promise2'
    'timer2'

    ————————————————————————————————————————

    //5、
    const promise1 = new Promise((resolve, reject) => {
      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)
    
    分析过程
    • 从上至下,先执行第一个new Promise中的函数,碰到setTimeout将它加入下一个宏任务列表
    • 跳出new Promise,碰到promise1.then这个微任务,但其状态还是为pending,这里理解为先不执行
    • promise2是一个新的状态为pending的Promise
    • 执行同步代码console.log('promise1'),且打印出的promise1的状态为pending
    • 执行同步代码console.log('promise2'),且打印出的promise2的状态为pending
    • 碰到第二个定时器,将其放入下一个宏任务列表
    • 第一轮宏任务执行结束,并且没有微任务需要执行,因此执行第二轮宏任务
    • 先执行第一个定时器里的内容,将promise1的状态改为resolved且保存结果并将之前的promise1.then推入微任务队列
    • 该定时器中没有其它的同步代码可执行,因此执行本轮的微任务队列,也就是promise1.then,它抛出了一个错误,且将promise2的状态设置为了rejected
    • 第一个定时器执行完毕,开始执行第二个定时器中的内容
    • 打印出'promise1',且此时promise1的状态为resolved
    • 打印出'promise2',且此时promise2的状态为rejected
    执行结果

    'promise1' Promise{<pending>}
    'promise2' Promise{<pending>}
    test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102
    'promise1' Promise{<resolved>: "success"}
    'promise2' Promise{<rejected>: Error: error!!!}

    ————————————————————————————————————————

    //6、
    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'
    test5.html:102 Uncaught (in promise) Error: error!!! at test.html:102
    'timer2'
    'promise1' Promise{<resolved>: "success"}
    'promise2' Promise{<rejected>: Error: error!!!}

    相关文章

      网友评论

          本文标题:promise 练习题(二)

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