Skip to content

事件循环

如何消除异步代码的传染性

js
function timeOut(rt, time = 1000) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(rt)
    }, time)
  })
}
async function m1() {
  let rt = await timeOut(1)
  return ++rt
}

async function m2() {
  let rt = await m1()
  return ++rt
}
async function m3() {
  let rt = await m2()
  return ++rt
}
async function main() {
  let rt = await m3()
  console.log(rt)
}
main() // 4

这个一个常见的场景: 因为 timeOut 函数是异步的,导致所有需要依赖其结果的函数都变成异步了。

对于函数式编程来说这个就很影响代码结构,在不改变原函数的情况下,消除异步的影响。

实现如下:

js
function timeOut(rt, time = 1000) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(rt)
    }, time)
  })
}
function m1() {
  let rt = timeOut(1)
  return ++rt
}

function m2() {
  let rt = m1()
  return ++rt
}
function m3() {
  let rt = m2()
  return ++rt
}
function main() {
  let rt = m3()
  console.log(rt)
}

function run(func) {
  const oldFetch = window.timeOut

  let cache = {
    status: 'pending',
    value: null
  }

  window.timeOut = function (...args) {
    if (cache.status === 'fulfilled') {
      return cache.value
    } else if (cache.status === 'rejected') {
      throw cache.value
    }

    const promise = oldFetch(...args).then(
      (res) => {
        cache.status = 'fulfilled'
        cache.value = res
      },
      (err) => {
        cache.status = 'rejected'
        cache.value = err
      }
    )
    throw promise
  }

  try {
    func()
  } catch (err) {
    if (err instanceof Promise) {
      err.then(func, func).finally(() => {
        window.timeOut = oldFetch
      })
    }
  }
}

run(main)

这个主要考验大家对 函数执行链 的理解 ,通过 throw 和 try catch 来打断调用链,再通过传递的 promise 来重新唤起调用链 。

这些题目都源自react中的 hooks、Suspense的实现引起的思考

本质上都是为了让函数更纯、让异步变同步、让副作用更好的管理

涉及到一些概念:比如 Continuation、CPS、Algebraic Effects

Released under the MIT License.