xxleyi / learning_list

聚集自己的学习笔记
10 stars 3 forks source link

JS yield + continuation 原理实现 async/await 异步 #216

Open xxleyi opened 4 years ago

xxleyi commented 4 years ago

看到一篇大神的回答,涉及到 continuation 的具体应用,酷毙:async/await proposal实现原理是什么? - 知乎

按照国际惯例:k 表示 continuation

大神代码改编一,抽出 next 函数让结构更易懂:

const yieldContinuation = generator => recursiveCore.call(generator)

const recursiveCore = function (feedback) {
  try {
    next(this, feedback)(v => recursiveCore.call(this, v))
  } catch { }
}

function next(generator, feedback) {
  const res = generator.next(feedback)
  if (res.done) throw Error("StopIteration")
  const yieldFunc = res.value
  return yieldFunc
}

const async_timeout = (data, time) => {
  return function (k) {
    setTimeout(() => k(data), time)
  }
}

function* fooGen() {
  const v1 = yield async_timeout("Hello ", 1000)
  console.warn(v1)

  const v2 = yield async_timeout("World", 10)
  console.warn(v1 + v2)
}

yieldContinuation(fooGen())

大神代码改编二,去掉 .call 的用法:

  const yieldContinuation = generator => recursiveCore(generator)

  const recursiveCore = (generator, feedback) => {
    try {
      next(generator, feedback)(v => recursiveCore(generator, v))
    } catch { }
  }

  function next(generator, feedback) {
    const res = generator.next(feedback)
    if (res.done) throw Error("StopIteration")
    const yieldFunc = res.value
    return yieldFunc
  }

  const async_timeout = (data, time) => {
    return function (k) {
      setTimeout(() => k(data), time)
    }
  }

  function* fooGen() {
    const v1 = yield async_timeout("Hello ", 1000)
    console.warn(v1)

    const v2 = yield async_timeout("World", 10)
    console.warn(v1 + v2)
  }

  function* barGen() {
    const v1 = yield async_timeout("async ", 800)
    console.warn(v1)

    const v2 = yield async_timeout("await", 300)
    console.warn(v1 + v2)
  }

  [fooGen(), barGen()].forEach(yieldContinuation)
xxleyi commented 4 years ago

复习 continuation,靠自己的理解和记忆独立建构,并优化命名

function yieldContinuation(generator) {
  recursiveCall(generator)
}

function recursiveCall(generator, feedback) {
  try {
    next(generator, feedback)(v => recursiveCall(generator, v))
  } catch { }
}

function next(generator, feedback) {
  const res = generator.next(feedback)
  if (res.done) throw Error('StopIteration')
  return res.value
}

function makeAsyncContinuation(value, time) {
  return k => setTimeout(k, time, value)
}

yieldContinuation(function* () {
  const v1 = yield makeAsyncContinuation("Hello1", 100)
  console.log(v1)
  const v2 = yield makeAsyncContinuation("World1", 1000)
  console.log(v2)
}())

yieldContinuation(function* () {
  const v1 = yield makeAsyncContinuation("Hello2", 300)
  console.log(v1)
  const v2 = yield makeAsyncContinuation("World2", 800)
  console.log(v2)
}())