【发布时间】: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