diff --git a/lib/init.lua b/lib/init.lua index 2f090d1..826ba35 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -1436,11 +1436,17 @@ function Promise.prototype:_finally(traceback, finallyHandler) self._unhandledRejection = false local promise = Promise._new(traceback, function(resolve, reject, onCancel) + local handlerPromise + onCancel(function() -- The finally Promise is not a proper consumer of self. We don't care about the resolved value. -- All we care about is running at the end. Therefore, if self has no other consumers, it's safe to -- cancel. We don't need to hold out cancelling just because there's a finally handler. self:_consumerCancelled(self) + + if handlerPromise then + handlerPromise:cancel() + end end) local finallyCallback = resolve @@ -1449,6 +1455,8 @@ function Promise.prototype:_finally(traceback, finallyHandler) local callbackReturn = finallyHandler(...) if Promise.is(callbackReturn) then + handlerPromise = callbackReturn + callbackReturn :finally(function(status) if status ~= Promise.Status.Rejected then diff --git a/lib/init.spec.lua b/lib/init.spec.lua index 51e8c57..b545b37 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -835,6 +835,18 @@ return function() expect(finallyRan).to.equal(true) expect(andThenRan).to.equal(false) end) + + it("should cancel returned promise if cancelled", function() + local internal = Promise.new(function() end) + + local promise = Promise.resolve():finally(function() + return internal + end) + + promise:cancel() + + expect(internal:getStatus()).to.equal(Promise.Status.Cancelled) + end) end) describe("Promise.all", function()