esnext.async-disposable-stack.constructor.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. 'use strict';
  2. // https://github.com/tc39/proposal-async-explicit-resource-management
  3. var $ = require('../internals/export');
  4. var DESCRIPTORS = require('../internals/descriptors');
  5. var getBuiltIn = require('../internals/get-built-in');
  6. var aCallable = require('../internals/a-callable');
  7. var anInstance = require('../internals/an-instance');
  8. var defineBuiltIn = require('../internals/define-built-in');
  9. var defineBuiltIns = require('../internals/define-built-ins');
  10. var defineBuiltInAccessor = require('../internals/define-built-in-accessor');
  11. var wellKnownSymbol = require('../internals/well-known-symbol');
  12. var InternalStateModule = require('../internals/internal-state');
  13. var addDisposableResource = require('../internals/add-disposable-resource');
  14. var V8_VERSION = require('../internals/environment-v8-version');
  15. var Promise = getBuiltIn('Promise');
  16. var SuppressedError = getBuiltIn('SuppressedError');
  17. var $ReferenceError = ReferenceError;
  18. var ASYNC_DISPOSE = wellKnownSymbol('asyncDispose');
  19. var TO_STRING_TAG = wellKnownSymbol('toStringTag');
  20. var ASYNC_DISPOSABLE_STACK = 'AsyncDisposableStack';
  21. var setInternalState = InternalStateModule.set;
  22. var getAsyncDisposableStackInternalState = InternalStateModule.getterFor(ASYNC_DISPOSABLE_STACK);
  23. var HINT = 'async-dispose';
  24. var DISPOSED = 'disposed';
  25. var PENDING = 'pending';
  26. var getPendingAsyncDisposableStackInternalState = function (stack) {
  27. var internalState = getAsyncDisposableStackInternalState(stack);
  28. if (internalState.state === DISPOSED) throw new $ReferenceError(ASYNC_DISPOSABLE_STACK + ' already disposed');
  29. return internalState;
  30. };
  31. var $AsyncDisposableStack = function AsyncDisposableStack() {
  32. setInternalState(anInstance(this, AsyncDisposableStackPrototype), {
  33. type: ASYNC_DISPOSABLE_STACK,
  34. state: PENDING,
  35. stack: []
  36. });
  37. if (!DESCRIPTORS) this.disposed = false;
  38. };
  39. var AsyncDisposableStackPrototype = $AsyncDisposableStack.prototype;
  40. defineBuiltIns(AsyncDisposableStackPrototype, {
  41. disposeAsync: function disposeAsync() {
  42. var asyncDisposableStack = this;
  43. return new Promise(function (resolve, reject) {
  44. var internalState = getAsyncDisposableStackInternalState(asyncDisposableStack);
  45. if (internalState.state === DISPOSED) return resolve(undefined);
  46. internalState.state = DISPOSED;
  47. if (!DESCRIPTORS) asyncDisposableStack.disposed = true;
  48. var stack = internalState.stack;
  49. var i = stack.length;
  50. var thrown = false;
  51. var suppressed;
  52. var handleError = function (result) {
  53. if (thrown) {
  54. suppressed = new SuppressedError(result, suppressed);
  55. } else {
  56. thrown = true;
  57. suppressed = result;
  58. }
  59. loop();
  60. };
  61. var loop = function () {
  62. if (i) {
  63. var disposeMethod = stack[--i];
  64. stack[i] = null;
  65. try {
  66. Promise.resolve(disposeMethod()).then(loop, handleError);
  67. } catch (error) {
  68. handleError(error);
  69. }
  70. } else {
  71. internalState.stack = null;
  72. thrown ? reject(suppressed) : resolve(undefined);
  73. }
  74. };
  75. loop();
  76. });
  77. },
  78. use: function use(value) {
  79. addDisposableResource(getPendingAsyncDisposableStackInternalState(this), value, HINT);
  80. return value;
  81. },
  82. adopt: function adopt(value, onDispose) {
  83. var internalState = getPendingAsyncDisposableStackInternalState(this);
  84. aCallable(onDispose);
  85. addDisposableResource(internalState, undefined, HINT, function () {
  86. return onDispose(value);
  87. });
  88. return value;
  89. },
  90. defer: function defer(onDispose) {
  91. var internalState = getPendingAsyncDisposableStackInternalState(this);
  92. aCallable(onDispose);
  93. addDisposableResource(internalState, undefined, HINT, onDispose);
  94. },
  95. move: function move() {
  96. var internalState = getPendingAsyncDisposableStackInternalState(this);
  97. var newAsyncDisposableStack = new $AsyncDisposableStack();
  98. getAsyncDisposableStackInternalState(newAsyncDisposableStack).stack = internalState.stack;
  99. internalState.stack = [];
  100. internalState.state = DISPOSED;
  101. if (!DESCRIPTORS) this.disposed = true;
  102. return newAsyncDisposableStack;
  103. }
  104. });
  105. if (DESCRIPTORS) defineBuiltInAccessor(AsyncDisposableStackPrototype, 'disposed', {
  106. configurable: true,
  107. get: function disposed() {
  108. return getAsyncDisposableStackInternalState(this).state === DISPOSED;
  109. }
  110. });
  111. defineBuiltIn(AsyncDisposableStackPrototype, ASYNC_DISPOSE, AsyncDisposableStackPrototype.disposeAsync, { name: 'disposeAsync' });
  112. defineBuiltIn(AsyncDisposableStackPrototype, TO_STRING_TAG, ASYNC_DISPOSABLE_STACK, { nonWritable: true });
  113. // https://github.com/tc39/proposal-explicit-resource-management/issues/256
  114. // can't be detected synchronously
  115. var SYNC_DISPOSE_RETURNING_PROMISE_RESOLUTION_BUG = V8_VERSION && V8_VERSION < 136;
  116. $({ global: true, constructor: true, forced: SYNC_DISPOSE_RETURNING_PROMISE_RESOLUTION_BUG }, {
  117. AsyncDisposableStack: $AsyncDisposableStack
  118. });