一学期的比赛生涯在 “” 中结束了, 无论如何; 开始了新学期的学习.那么这学期主攻学业, 但是前端还是要在子任务进度下慢慢推进, 本文算是前端继续学习的一个开端~

面试面什么?

image-20230920104116918

  • 熟练使用Promise封装代码,如封装axios,Promise级联使用,掌握async、await的用法
  • 掌握Promise静态方法的使用场景、用法,Promise.all、Promise.allSettled、Promise.race、Promise.any、Promise.resolve、Promise.reject
  • 手写Promise.all、Promise.race、Promise.allSettled
  • 手写Promise.any、Promise.last、Promise.queue
  • 并发请求限制数量封装
  • 实现Promisify
  • Promise 微任务输出、async/await 微任务输出
  • 理解Promise A+规范,手写Promise

手写 Promise.all 原理

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

image-20230920104826227

image-20230920104612738

手写 Promise.race 原理

Promise.race(iterable)方法返回一个promise, 一旦迭代器中的某个 promise resolve 或者 reject, 返回的 promise 就会 resolve 或reject.

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

手写Promise.race

手写 Promise.allSettled 原理

Promise.allSettled() 方法返回一个在所有给定的promise都已 fuldilled 或 rejected 后的 promise, 并带有一个对象数组, 每个对象表示对应的 promise 结果.

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

Promise.allSettled

手写 Promise.any 原理

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

手写Promise.any

手写并发控制

  • 使用闭包优化并发请求结果顺序

宏任务、微任务原理

运行顺序

  • 先运行同步代码
  • 再扫描微队列依次运行并清空全部任务
  • 扫描宏队列拿出一个任务运行
  • 再扫描微队列依次运行并清空全部任务
  • 扫描宏队列拿出一个任务运行…..
  • 直到两个队列都为空

同步与放入宏队列

  • setTimeout(fn, t) 本身是同步代码,作用是创建一个定时器
  • t毫秒后把fn放入宏队列
  • new Promise(function fn(resolve, reject) { ...}) 会立即运行fn,其中**fn里也是同步代码**

放入微队列

  • 对于处于pending状态的Promise对象p,内部状态的resolve,才会触发p.then(fn)中的fn加入微队列
  • 对于处于fulfilled状态的Promise对象p, 执行p.then(fn)会立即让fn加入微队列

思路

宏任务、微任务案例1

原始代码,输出什么?

改造后,所有的函数都加个名字,便于分析

执行过程:

  1. 执行同步代码创建计时器,并立即加入到宏队列。 此时宏队列【f1】,微队列【】;
  2. 创建Promise,运行同步代码f2()。运行resolve()会触发f3加入微队列。此时宏队列【f1】,微队列【f3】。再输出2;
  3. 运行同步代码输出4。同步代码执行完毕,扫描微队列,执行全部任务,执行f3(),输出3;
  4. 拿出一个宏队列任务,执行f1(),输出1。此时队列都为空。

image-20230922095000652

案例1

宏任务、微任务案例2

输出什么?

  • 执行同步代码创建Promise对象,运行同步代码f1()。输出1,创建定时器,立即把f2加入宏队列。运行resolve(1),触发f3加入微队列。此时宏队列【f2】,微队列【f3】;
  • 创建定时器,立即把f4加入宏队列。此时宏队列【f2, f4】,微队列【f3】;
  • 运行同步代码输出5。同步代码执行完毕;
  • 扫描微队列,拿出并执行全部任务,执行f3(),输出3;
  • 拿出一个宏队列任务,执行f2(),输出2。扫描微队列为空,再扫描宏队列拿出f4执行,输出4。此时队列都为空。

image-20230922094932033

案例2

宏任务、微任务案例3

输出什么?

  1. 创建定时器,立即把f1加入宏队列。此时宏队列【f1】,微队列【】;
  2. 创建Promise对象,执行同步代码f2()。执行resolve() 触发f3加入微队列。之后输出2。此时宏队列【f1】,微队列【f3】;
  3. 运行同步代码输出6。同步代码执行完毕;
  4. 扫描微队列,拿出并执行全部任务。先执行f3(),输出3;Promise.resolve().then(f4) 立即把f4加入微队列。此时宏队列【f1】,微队列【f4】。微队列不为空,拿出f4执行,输出4。f4执行完导致当前状态fulfilled,触发f5加入微队列。拿出f5继续执行,触发f6立即加入微队列。拿出并执行f6,输出5。此时宏队列为【f1】,微队列为空
  5. 扫码宏队列,拿出运行f1,输出1。

image-20230922094902186

案例3

宏任务、微任务案例4

  1. 输出1;
  2. 创建定时器,立即把f1加入宏队列。此时宏队列【f1】,微队列【】;
  3. 输出6;
  4. 扫描微队列,为空。扫描宏队列,取出f1运行。输出2;f2立即加入微队列。此时宏队列【】,微队列【f2】。
  5. 扫描微队列,拿出并执行全部任务。执行f2(),输出3;创建计时器,立即把f3加入宏队列。f2执行完毕时导致当前promise fulfilled,触发f4加入微队列。此时宏队列【f3】,微队列【f4】。微队列不为空,继续拿出f4执行,输出5。此时宏队列【f3】,微队列【】
  6. 扫码宏队列,运行f3,输出4。结束。

image-20230922094813849

案例4