Skip to content

Commit b6a36de

Browse files
Josh-Cenabakkotgithub-actions[bot]
authored
Reference for stage 3 explicit-resource-management (mdn#38027)
* Reference for stage 3 explicit-resource-management * DisposableStack * Iterator disposal * AsyncDisposableStack * await using example * Example for using * Final updates * Apply suggestions from code review Co-authored-by: Kevin Gibbons <bakkot@gmail.com> * Consistently use the name "disposer" instead * Address more reviews * Migrate sidebar * Fill in holes * Update files/en-us/web/javascript/reference/global_objects/symbol/asyncdispose/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update files/en-us/web/javascript/guide/resource_management/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fixes * Update index.md * Apply suggestions from code review Co-authored-by: Kevin Gibbons <bakkot@gmail.com> * Update index.md * Update index.md * Update index.md * Update index.md * Update index.md * Update index.md --------- Co-authored-by: Kevin Gibbons <bakkot@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent ce31fcc commit b6a36de

File tree

44 files changed

+2968
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2968
-7
lines changed

files/en-us/web/javascript/guide/internationalization/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ page-type: guide
55
sidebar: jssidebar
66
---
77

8-
{{PreviousNext("Web/JavaScript/Guide/Iterators_and_generators", "Web/JavaScript/Guide/Modules")}}
8+
{{PreviousNext("Web/JavaScript/Guide/Resource_management", "Web/JavaScript/Guide/Modules")}}
99

1010
The {{jsxref("Intl")}} object is the namespace for the ECMAScript Internationalization API, which provides a wide range of locale- and culture-sensitive data and operations.
1111

@@ -846,4 +846,4 @@ setInterval(renderTime, 500);
846846
847847
{{EmbedLiveSample("display_names", "", 300)}}
848848
849-
{{PreviousNext("Web/JavaScript/Guide/Iterators_and_generators", "Web/JavaScript/Guide/Modules")}}
849+
{{PreviousNext("Web/JavaScript/Guide/Resource_management", "Web/JavaScript/Guide/Modules")}}

files/en-us/web/javascript/guide/iterators_and_generators/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ page-type: guide
55
sidebar: jssidebar
66
---
77

8-
{{PreviousNext("Web/JavaScript/Guide/Typed_arrays", "Web/JavaScript/Guide/Internationalization")}}
8+
{{PreviousNext("Web/JavaScript/Guide/Typed_arrays", "Web/JavaScript/Guide/Resource_management")}}
99

1010
Iterators and Generators bring the concept of iteration directly into the core language and provide a mechanism for customizing the behavior of {{jsxref("Statements/for...of", "for...of")}} loops.
1111

@@ -235,4 +235,4 @@ If the exception is not caught from within the generator, it will propagate up t
235235

236236
Generators have a {{jsxref("Generator/return", "return()")}} method that returns the given value and finishes the generator itself.
237237

238-
{{PreviousNext("Web/JavaScript/Guide/Typed_arrays", "Web/JavaScript/Guide/Internationalization")}}
238+
{{PreviousNext("Web/JavaScript/Guide/Typed_arrays", "Web/JavaScript/Guide/Resource_management")}}

files/en-us/web/javascript/guide/resource_management/index.md

Lines changed: 447 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
title: AsyncDisposableStack.prototype.adopt()
3+
slug: Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/adopt
4+
page-type: javascript-instance-method
5+
browser-compat: javascript.builtins.AsyncDisposableStack.adopt
6+
sidebar: jsref
7+
---
8+
9+
The **`adopt()`** method of {{jsxref("AsyncDisposableStack")}} instances registers a value that doesn't implement the async disposable protocol to the stack by providing a custom disposer function.
10+
11+
See {{jsxref("DisposableStack.prototype.adopt()")}} for general information about the `adopt()` method.
12+
13+
## Syntax
14+
15+
```js-nolint
16+
adopt(value, onDispose)
17+
```
18+
19+
### Parameters
20+
21+
- `value`
22+
- : Any value to be registered to the stack.
23+
- `onDispose`
24+
- : A function that will be called when the stack is disposed. The function receives `value` as its only argument, and it can return a promise which gets awaited.
25+
26+
### Return value
27+
28+
The same `value` that was passed in.
29+
30+
### Exceptions
31+
32+
- {{jsxref("TypeError")}}
33+
- : Thrown if `onDispose` is not a function.
34+
- {{jsxref("ReferenceError")}}
35+
- : Thrown if the stack is already disposed.
36+
37+
## Examples
38+
39+
### Using adopt()
40+
41+
This function creates a file handle (as a Node.js [`FileHandle`](https://nodejs.org/api/fs.html#class-filehandle)), that gets closed when the function completes. We suppose that the file handle does not implement the async disposable protocol (in reality it does), so we use `adopt()` to register it to the stack. Because the `handle.close()` method returns a promise, we need to use an `AsyncDisposableStack` so that the disposal gets awaited.
42+
43+
```js
44+
async function readFile(path) {
45+
await using disposer = new AsyncDisposableStack();
46+
const handle = disposer.adopt(
47+
fs.open(path),
48+
async (handle) => await handle.close(),
49+
);
50+
const data = await handle.read();
51+
// The handle.close() method is called and awaited here before exiting
52+
return data;
53+
}
54+
```
55+
56+
## Specifications
57+
58+
{{Specifications}}
59+
60+
## Browser compatibility
61+
62+
{{Compat}}
63+
64+
## See also
65+
66+
- [JavaScript resource management](/en-US/docs/Web/JavaScript/Guide/Resource_management)
67+
- {{jsxref("AsyncDisposableStack")}}
68+
- {{jsxref("AsyncDisposableStack.prototype.defer()")}}
69+
- {{jsxref("AsyncDisposableStack.prototype.use()")}}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: AsyncDisposableStack() constructor
3+
slug: Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/AsyncDisposableStack
4+
page-type: javascript-constructor
5+
browser-compat: javascript.builtins.AsyncDisposableStack.AsyncDisposableStack
6+
sidebar: jsref
7+
---
8+
9+
The **`AsyncDisposableStack()`** constructor creates {{jsxref("AsyncDisposableStack")}} objects.
10+
11+
## Syntax
12+
13+
```js-nolint
14+
new AsyncDisposableStack()
15+
```
16+
17+
> [!NOTE]
18+
> `AsyncDisposableStack()` can only be constructed with [`new`](/en-US/docs/Web/JavaScript/Reference/Operators/new). Attempting to call it without `new` throws a {{jsxref("TypeError")}}.
19+
20+
### Parameters
21+
22+
None.
23+
24+
### Return value
25+
26+
A new `AsyncDisposableStack` object.
27+
28+
## Examples
29+
30+
### Creating an AsyncDisposableStack
31+
32+
```js
33+
const disposer = new AsyncDisposableStack();
34+
disposer.defer(() => console.log("Disposed!"));
35+
await disposer.disposeAsync();
36+
// Logs: Disposed!
37+
```
38+
39+
## Specifications
40+
41+
{{Specifications}}
42+
43+
## Browser compatibility
44+
45+
{{Compat}}
46+
47+
## See also
48+
49+
- [JavaScript resource management](/en-US/docs/Web/JavaScript/Guide/Resource_management)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: AsyncDisposableStack.prototype.defer()
3+
slug: Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/defer
4+
page-type: javascript-instance-method
5+
browser-compat: javascript.builtins.AsyncDisposableStack.defer
6+
sidebar: jsref
7+
---
8+
9+
The **`defer()`** method of {{jsxref("AsyncDisposableStack")}} instances takes a callback function to be called and awaited when the stack is disposed.
10+
11+
See {{jsxref("DisposableStack.prototype.defer()")}} for general information about the `defer()` method.
12+
13+
## Syntax
14+
15+
```js-nolint
16+
defer(onDispose)
17+
```
18+
19+
### Parameters
20+
21+
- `onDispose`
22+
- : A function that will be called when the stack is disposed. The function receives no arguments and can return a promise which gets awaited.
23+
24+
### Return value
25+
26+
None ({{jsxref("undefined")}}).
27+
28+
### Exceptions
29+
30+
- {{jsxref("TypeError")}}
31+
- : Thrown if `onDispose` is not a function.
32+
- {{jsxref("ReferenceError")}}
33+
- : Thrown if the stack is already disposed.
34+
35+
## Examples
36+
37+
### Using defer()
38+
39+
One use case of `defer()` is to do something unrelated to resource freeing during scope exit, such as logging a message.
40+
41+
```js
42+
async function doSomething() {
43+
await using disposer = new AsyncDisposableStack();
44+
disposer.defer(async () => {
45+
await fs.writeFile("log.txt", "All resources freed successfully");
46+
});
47+
// Other code that claims and frees more data
48+
}
49+
```
50+
51+
## Specifications
52+
53+
{{Specifications}}
54+
55+
## Browser compatibility
56+
57+
{{Compat}}
58+
59+
## See also
60+
61+
- [JavaScript resource management](/en-US/docs/Web/JavaScript/Guide/Resource_management)
62+
- {{jsxref("AsyncDisposableStack")}}
63+
- {{jsxref("AsyncDisposableStack.prototype.adopt()")}}
64+
- {{jsxref("AsyncDisposableStack.prototype.use()")}}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
title: AsyncDisposableStack.prototype.disposeAsync()
3+
slug: Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/disposeAsync
4+
page-type: javascript-instance-method
5+
browser-compat: javascript.builtins.AsyncDisposableStack.disposeAsync
6+
sidebar: jsref
7+
---
8+
9+
The **`disposeAsync()`** method of {{jsxref("AsyncDisposableStack")}} instances disposes this stack by calling all disposers registered to it in reverse order of registration, awaiting for each one's completion before calling the next one. If the stack is already disposed, this method does nothing.
10+
11+
It performs the same action as `await using disposer = new AsyncDisposableStack()` at scope exit. It can be used if you need to clean up at a point other than scope exit.
12+
13+
## Syntax
14+
15+
```js-nolint
16+
disposeAsync()
17+
```
18+
19+
### Parameters
20+
21+
None.
22+
23+
### Return value
24+
25+
A new {{jsxref("Promise")}} that resolves with `undefined` when all registered disposers have completed in sequence.
26+
27+
### Exceptions
28+
29+
`disposeAsync()` never synchronously throws an error. The returned promise may reject with one of the following errors:
30+
31+
- {{jsxref("SuppressedError")}}
32+
- : Thrown if multiple disposers in the stack threw an error. If only one error is thrown, it is rethrown as-is. Otherwise, for each additional error, a new {{jsxref("SuppressedError")}} is created, with the original error as the `suppressed` property, and the new error as the `error` property.
33+
34+
## Examples
35+
36+
### Disposing a stack
37+
38+
Here we push three disposers to the stack, using the {{jsxref("AsyncDisposableStack/use", "use()")}}, {{jsxref("AsyncDisposableStack/adopt", "adopt()")}}, and {{jsxref("AsyncDisposableStack/defer", "defer()")}} methods. When `disposeAsync()` is called, the disposers are called in reverse order of registration.
39+
40+
Note that usually you don't need to call `disposeAsync()` manually. Declare the stack with {{jsxref("Statements/await_using", "await using")}}, and its [`[Symbol.asyncDispose]()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/Symbol.asyncDispose) method will be automatically called when the stack goes out of scope.
41+
42+
```js
43+
class Resource {
44+
#doDisposal() {
45+
// Imagine more meaningful disposal logic here
46+
return new Promise((resolve) => {
47+
setTimeout(resolve, 1000);
48+
});
49+
}
50+
async dispose() {
51+
await this.#doDisposal();
52+
console.log("Resource disposed");
53+
}
54+
async [Symbol.asyncDispose]() {
55+
await this.#doDisposal();
56+
console.log("Resource disposed via Symbol.asyncDispose");
57+
}
58+
}
59+
60+
async function doSomething() {
61+
const disposer = new AsyncDisposableStack();
62+
const resource = disposer.use(new Resource());
63+
const resource2 = disposer.adopt(new Resource(), (resource) =>
64+
resource.dispose(),
65+
);
66+
disposer.defer(() => console.log("Deferred disposer"));
67+
disposer.disposeAsync();
68+
// Logs in order:
69+
// Deferred disposer
70+
// Resource disposed
71+
// Resource disposed via Symbol.dispose
72+
}
73+
74+
doSomething();
75+
```
76+
77+
## Specifications
78+
79+
{{Specifications}}
80+
81+
## Browser compatibility
82+
83+
{{Compat}}
84+
85+
## See also
86+
87+
- [JavaScript resource management](/en-US/docs/Web/JavaScript/Guide/Resource_management)
88+
- {{jsxref("AsyncDisposableStack")}}
89+
- {{jsxref("AsyncDisposableStack.prototype.adopt()")}}
90+
- {{jsxref("AsyncDisposableStack.prototype.defer()")}}
91+
- {{jsxref("AsyncDisposableStack.prototype.use()")}}
92+
- [`AsyncDisposableStack.prototype[Symbol.asyncDispose]()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/Symbol.asyncDispose)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
title: AsyncDisposableStack.prototype.disposed
3+
slug: Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/disposed
4+
page-type: javascript-instance-accessor-property
5+
browser-compat: javascript.builtins.AsyncDisposableStack.disposed
6+
sidebar: jsref
7+
---
8+
9+
The **`disposed`** accessor property of {{jsxref("AsyncDisposableStack")}} instances returns a boolean indicating whether or not this `AsyncDisposableStack` has been disposed or moved by doing any of the following:
10+
11+
- Calling its {{jsxref("AsyncDisposableStack/disposeAsync", "disposeAsync()")}} method
12+
- Calling its {{jsxref("AsyncDisposableStack/move", "move()")}} method
13+
- Declaring it with {{jsxref("Statements/await_using", "await using")}} and letting the variable go out of scope, which automatically calls the [`[Symbol.asyncDispose]()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncDisposableStack/Symbol.asyncDispose) method.
14+
15+
## Examples
16+
17+
### Checking if a stack is disposed
18+
19+
```js
20+
const disposer = new AsyncDisposableStack();
21+
console.log(disposer.disposed); // false
22+
await disposer.disposeAsync();
23+
console.log(disposer.disposed); // true
24+
```
25+
26+
## Specifications
27+
28+
{{Specifications}}
29+
30+
## Browser compatibility
31+
32+
{{Compat}}
33+
34+
## See also
35+
36+
- [JavaScript resource management](/en-US/docs/Web/JavaScript/Guide/Resource_management)

0 commit comments

Comments
 (0)