finally.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. "use strict";
  2. module.exports = function(Promise, tryConvertToPromise) {
  3. var util = require("./util");
  4. var CancellationError = Promise.CancellationError;
  5. var errorObj = util.errorObj;
  6. function PassThroughHandlerContext(promise, type, handler) {
  7. this.promise = promise;
  8. this.type = type;
  9. this.handler = handler;
  10. this.called = false;
  11. this.cancelPromise = null;
  12. }
  13. PassThroughHandlerContext.prototype.isFinallyHandler = function() {
  14. return this.type === 0;
  15. };
  16. function FinallyHandlerCancelReaction(finallyHandler) {
  17. this.finallyHandler = finallyHandler;
  18. }
  19. FinallyHandlerCancelReaction.prototype._resultCancelled = function() {
  20. checkCancel(this.finallyHandler);
  21. };
  22. function checkCancel(ctx, reason) {
  23. if (ctx.cancelPromise != null) {
  24. if (arguments.length > 1) {
  25. ctx.cancelPromise._reject(reason);
  26. } else {
  27. ctx.cancelPromise._cancel();
  28. }
  29. ctx.cancelPromise = null;
  30. return true;
  31. }
  32. return false;
  33. }
  34. function succeed() {
  35. return finallyHandler.call(this, this.promise._target()._settledValue());
  36. }
  37. function fail(reason) {
  38. if (checkCancel(this, reason)) return;
  39. errorObj.e = reason;
  40. return errorObj;
  41. }
  42. function finallyHandler(reasonOrValue) {
  43. var promise = this.promise;
  44. var handler = this.handler;
  45. if (!this.called) {
  46. this.called = true;
  47. var ret = this.isFinallyHandler()
  48. ? handler.call(promise._boundValue())
  49. : handler.call(promise._boundValue(), reasonOrValue);
  50. if (ret !== undefined) {
  51. promise._setReturnedNonUndefined();
  52. var maybePromise = tryConvertToPromise(ret, promise);
  53. if (maybePromise instanceof Promise) {
  54. if (this.cancelPromise != null) {
  55. if (maybePromise._isCancelled()) {
  56. var reason =
  57. new CancellationError("late cancellation observer");
  58. promise._attachExtraTrace(reason);
  59. errorObj.e = reason;
  60. return errorObj;
  61. } else if (maybePromise.isPending()) {
  62. maybePromise._attachCancellationCallback(
  63. new FinallyHandlerCancelReaction(this));
  64. }
  65. }
  66. return maybePromise._then(
  67. succeed, fail, undefined, this, undefined);
  68. }
  69. }
  70. }
  71. if (promise.isRejected()) {
  72. checkCancel(this);
  73. errorObj.e = reasonOrValue;
  74. return errorObj;
  75. } else {
  76. checkCancel(this);
  77. return reasonOrValue;
  78. }
  79. }
  80. Promise.prototype._passThrough = function(handler, type, success, fail) {
  81. if (typeof handler !== "function") return this.then();
  82. return this._then(success,
  83. fail,
  84. undefined,
  85. new PassThroughHandlerContext(this, type, handler),
  86. undefined);
  87. };
  88. Promise.prototype.lastly =
  89. Promise.prototype["finally"] = function (handler) {
  90. return this._passThrough(handler,
  91. 0,
  92. finallyHandler,
  93. finallyHandler);
  94. };
  95. Promise.prototype.tap = function (handler) {
  96. return this._passThrough(handler, 1, finallyHandler);
  97. };
  98. return PassThroughHandlerContext;
  99. };