diff --git a/lib/init.lua b/lib/init.lua index 03675b1..24bae42 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -1206,7 +1206,7 @@ function Promise.prototype:_andThen(traceback, successHandler, failureHandler) self._unhandledRejection = false -- Create a new promise to follow this part of the chain - return Promise._new(traceback, function(resolve, reject) + return Promise._new(traceback, function(resolve, reject, onCancel) -- Our default callbacks just pass values onto the next promise. -- This lets success and failure cascade correctly! @@ -1224,6 +1224,15 @@ function Promise.prototype:_andThen(traceback, successHandler, failureHandler) -- If we haven't resolved yet, put ourselves into the queue table.insert(self._queuedResolve, successCallback) table.insert(self._queuedReject, failureCallback) + + onCancel(function() + -- These are guaranteed to exist because the cancellation handler is guaranteed to only + -- be called at most once + if self._status == Promise.Status.Started then + table.remove(self._queuedResolve, table.find(self._queuedResolve, successCallback)) + table.remove(self._queuedReject, table.find(self._queuedReject, failureCallback)) + end + end) elseif self._status == Promise.Status.Resolved then -- This promise has already resolved! Trigger success immediately. successCallback(unpack(self._values, 1, self._valuesLength)) diff --git a/lib/init.spec.lua b/lib/init.spec.lua index a6599a0..0edcea9 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -543,6 +543,27 @@ return function() expect(y).to.equal(2) expect(z).to.equal(3) end) + + it("should not call queued callbacks from a cancelled sub-promise", function() + local resolve + local count = 0 + + local root = Promise.new(function(r) + resolve = r + end) + + root:andThen(function() + count += 1 + end) + + root:andThen(function() + count += 1 + end):cancel() + + resolve("foo") + + expect(count).to.equal(1) + end) end) describe("Promise:cancel", function()