我一直在搞砸取消承诺的想法,这是一种使用高阶函数的透明方式。我想出了这个:
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)
})发布于 2020-05-03 21:55:31
一个问题是then should take two parameters to deal with rejections。
至于为什么会超时:您使用的是await promise,但是await使用的是then,而您的promise被取消了,因此它从不调用回调。取消的承诺应该调用onreject回调,然后您的fnGetter应该忽略该取消错误,只对那些实际上期望您取消的回调忽略该取消错误。
发布于 2020-05-03 19:22:44
我想我知道发生了什么。从阅读中看,await只需要后续的代码,将其封装到一个函数中,然后将该函数传递到正在等待的任何东西的then方法中。如果是这样的话,那么我的代码就正常工作了,expect语句永远不会运行,因为我的承诺(等待中的承诺)被取消了。这就是为什么使用setTimeout运行测试的原因。
下面是我所指的功能的一个基本示例。
const func = async () => {
await { then: () => console.log("test") }
console.log("after")
}上面的代码打印"test",从不打印"after",因为console.log("after")被包装在函数中并传递给对象的then方法,后者从不调用它。
https://stackoverflow.com/questions/61578973
复制相似问题