【问题标题】:Why does my "thenable" function time out?为什么我的“thenable”函数会超时?
【发布时间】:2020-05-03 17:40:22
【问题描述】:

我一直认为取消承诺是一种使用高阶函数的透明方式。我想出了这个:

export const fnGetter = state => fn => (...args) => {
  if (!state.canceled) return fn(...args)
  return Promise.resolve()
}

export const cancelable = (promise, state = {}) => {
  const getFn = fnGetter(state)

  return {
    then: fn => cancelable(promise.then(getFn(fn)), state),
    catch: fn => cancelable(promise.catch(getFn(fn)), state),
    cancel: () => {
      state.canceled = true
    }
  }
}

export const withCancel = promiseReturningFn => (...args) =>
  cancelable(promiseReturningFn(...args))

这里有一些单元测试,我正在验证我想要的行为。

const delay = withCancel(ms => new Promise(run => setTimeout(run, ms)))

test('works like normal promise when not canceled', async () => {
  const first = jest.fn()
  const second = jest.fn()

  await delay(1000).then(first).then(second)

  expect(first).toHaveBeenCalledTimes(1)
  expect(second).toHaveBeenCalledTimes(1)
})

test('when ignored, does not call callbacks', async () => {
  const first = jest.fn()
  const second = jest.fn()

  const promise = delay(1000).then(first).then(second)
  promise.cancel()

  await promise

  expect(first).not.toHaveBeenCalled()
  expect(second).not.toHaveBeenCalled()
})

我不知道为什么第一个测试通过了,但是在第二个单元测试中调用 .cancel() 会导致超时。

编辑

认为这与await 在后台处理then 方法的方式有关。我现在只需要帮助。我希望它与异步等待兼容。这是一个不依赖await的传递版本。

test('when ignored, does not call callbacks', async () => {
  const first = jest.fn()
  const second = jest.fn()

  const promise = delay(1000).then(first).then(second)
  promise.cancel()

  setTimeout(() => {
    expect(first).not.toHaveBeenCalled()
    expect(second).not.toHaveBeenCalled()
  }, 2000)
})

【问题讨论】:

  • 如果你还没有这样做,我建议你阅读this
  • 我没有读过这个。给了我一些想法。谢谢。

标签: javascript promise async-await cancellation


【解决方案1】:

一个问题是then should take two parameters to deal with rejections

至于为什么超时:您使用的是await promise,但await 确实使用了then,并且您的promise 被取消,因此它永远不会调用它的回调。已取消的承诺应调用 onreject 回调,然后您的 fnGetter 应仅针对那些实际期望您取消的回调忽略该取消错误。

【讨论】:

    【解决方案2】:

    我想我知道发生了什么。从阅读来看,await 似乎只是获取后续代码,将其包装到一个函数中,然后将该函数传递给正在等待的 then 方法。如果是这种情况,那么我的代码正在运行,并且 expect 语句永远不会运行,因为我的承诺(正在等待的承诺)被取消了。这就是使用 setTimeout 运行测试的原因。

    这是我所指的功能的一个基本示例。

    const func = async () => {
      await { then: () => console.log("test") }
      console.log("after")
    }
    

    上面的代码打印"test",从不打印"after",因为console.log("after")被包装在一个函数中并传递给对象的then方法,该方法从不调用它。

    【讨论】:

      猜你喜欢
      • 2020-11-26
      • 2019-09-17
      • 2016-06-28
      • 2012-09-18
      • 2021-09-30
      • 2019-05-22
      • 1970-01-01
      • 2021-01-27
      • 2018-03-26
      相关资源
      最近更新 更多