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高级程序设计》(第四版)

posted @ 2021-09-26 16:25  叶际参差  阅读(245)  评论(0编辑  收藏  举报