ChenPt / dailyNote

dailyNode for myself
https://github.com/ChenPt/dailyNote/issues
0 stars 0 forks source link

实现LazyMan过程中,学习到的queueMicrotask方法 #46

Open ChenPt opened 2 years ago

ChenPt commented 2 years ago

今天中午做了一个打卡的题目,LazyMan,题目大概是

LazyMan('Peter').sleep(5).eat(dinner)
// 输出如下
// Hi Peter!
// (间隔了5s)
// wake up after 5
// eat dinner

LazyMan('Juily').eat('lanuch').sleepFirst(5)
// 输出如下
// (间隔了5s)
// wake up after 5
// Hi Juily!
// eat lanuch
  1. 思路:基于Promise的链式调用,function链式执行需要返回当前的上下文。
  2. 难点/考察点:由于需要实现sleepFirst,所以需要维护一个task数组。sleepFirst代表着将一个sleep的任务推到数组最前面。
  3. 具体流程:先收集所有任务,收集任务是同步的操作,在创建一个异步任务,负责依次执行task数组里的task。
const log = console.log
const sleepTask = (d) => () => new Promise((resolve) => setTimeout(() => resolve(log(`Wake up after ${d}`)), d * 1000))
function LazyMan(name) {
  const ctx = {
    sleep: (d) => {
      tasks.push(sleepTask(d))
      return ctx
    },
    sleepFirst: (d) => {
      tasks.unshift(sleepTask(d))
      return ctx
    },
    eat: (s) => {
      tasks.push(() => log(`Eat ${s}`))
      return ctx
    },
  }
  const tasks = [() => log(`Hi! This is ${name}!`)]
  const run = () => {
    // 通过setTimeout来生成一个macrotask。依次执行当前tasks里存储的任务
    setTimeout(async () => {
      while(tasks.length) {
        await tasks.shift()()
      }
    }, 0)
  }
  run()
  return ctx
}

在 JavaScript 中可以通过 queueMicrotask() 使用微任务,浏览器和nodejs宿主环境都支持这个api,node >= 11.0,浏览器的支持情况如下图 所以以后为了创建异步任务,无需再用setTimeout了,尽管使用queueMicrotask来创建一个microtask