UNPKG

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