Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Promises cancel recursively
  • Loading branch information
mweststrate committed Mar 12, 2018
1 parent 9e805b5 commit fe8131c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/api/flow.ts
Expand Up @@ -118,12 +118,14 @@ export function createFlowGenerator(name: string, generator: Function) {
const runId = ++generatorId
const gen = action(`${name} - runid: ${runId} - init`, generator).apply(ctx, args)
let rejector: (error: any) => void
let pendingPromise: CancellablePromise<any> | undefined = undefined

const res = new Promise(function(resolve, reject) {
let stepId = 0
rejector = reject

function onFulfilled(res: any) {
pendingPromise = undefined
let ret
try {
ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.next).call(
Expand All @@ -138,6 +140,7 @@ export function createFlowGenerator(name: string, generator: Function) {
}

function onRejected(err: any) {
pendingPromise = undefined
let ret
try {
ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.throw).call(
Expand All @@ -155,14 +158,17 @@ export function createFlowGenerator(name: string, generator: Function) {
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100
if (!ret.value || typeof ret.value.then !== "function")
return fail("Only promises can be yielded to asyncAction, got: " + ret)
return ret.value.then(onFulfilled, onRejected)
pendingPromise = ret.value
return pendingPromise!.then(onFulfilled, onRejected)
}

onFulfilled(undefined) // kick off the process
}) as any

res.cancel = action(`${name} - runid: ${runId} - cancel`, function() {
try {
if (pendingPromise && typeof pendingPromise.cancel === "function")
pendingPromise.cancel()
gen.return()
rejector(new Error("FLOW_CANCELLED"))
} catch (e) {
Expand Down
37 changes: 37 additions & 0 deletions test/base/flow.js
Expand Up @@ -280,3 +280,40 @@ test("flows can be cancelled - 5 - return before cancel", done => {
)
promise.cancel() // no-op
})

test("flows can be cancelled - 5 - flows cancel recursively", done => {
let flow1cancelled = false
let flow2cancelled = false
let stepsReached = 0

const flow1 = flow(function*() {
try {
yield Promise.resolve()
stepsReached++
} finally {
flow1cancelled = true
}
})

const flow2 = flow(function*() {
try {
yield flow1()
stepsReached++
} finally {
flow2cancelled = true
}
})

const p = flow2()
p.then(
() => fail(),
err => {
expect("" + err).toBe("Error: FLOW_CANCELLED")
expect(stepsReached).toBe(0)
expect(flow2cancelled).toBeTruthy()
expect(flow1cancelled).toBeTruthy()
done()
}
)
p.cancel()
})

0 comments on commit fe8131c

Please sign in to comment.