DisposableStack.prototype.move()
move()
方法是 DisposableStack
实例的一个方法,它创建一个新的 DisposableStack
实例,该实例包含与当前堆栈相同的处置器,然后将当前堆栈标记为已处置,而不调用任何处置器。
语法
js
move()
参数
无。
返回值
一个新的 DisposableStack
实例。
异常
ReferenceError
-
如果堆栈已被处置,则抛出异常。
描述
move()
的主要目的是能够将处置的责任从当前作用域转移出去。例如,你的函数可以声明对某些资源的所有权,并在发生错误时处置它们;如果一切顺利完成,则返回这些资源并将所有权转移给调用者。
当使用 move()
转移所有权时,调用 move()
应该是你的控制流中的最后一步,因为在你通过 move()
放弃所有权和调用者从返回值中获取所有权之间,将没有中间拥有者。
js
let resource1;
function init() {
using disposer = new DisposableStack();
resource1 = disposer.use(getResource1());
// ...
// Drop ownership immediately before returning
return disposer.move();
}
// Pick up ownership immediately after returning
using disposer = init();
js
let resource1;
function init() {
using disposer = new DisposableStack();
resource1 = disposer.use(getResource1());
// ...
const newDisposer = disposer.move();
// If someone adds code in between these lines and an error occurs,
// there would be no owner to free resource1
return newDisposer;
}
using disposer = init();
也要注意以下模式,尽管使用“好”的模式在许多情况下可能非常笨拙
js
function init() {
using disposer = new DisposableStack();
const resource1 = disposer.use(getResource1());
// ...
return { disposer: disposer.move(), resource1 };
}
const { resource1, ...rest } = init();
// If someone adds code in between these lines and an error occurs,
// there would be no owner to free resource1
using disposer = rest.disposer;
move()
也可以用于条件处置,在某些情况下你可能根本不想处置资源。例如:
js
using disposer = new DisposableStack();
const server = disposer.use(makeServer());
await server.init();
if (server.ready) {
// Successfully initialized server; it now should live through the rest
// of the program. Drop its disposer and don't pick it up. It will no
// longer be disposed at all.
disposer.move();
}
// If we reach the end of the scope without running disposer.move(),
// then server isn't ready for any reason, and we dispose its resources
// by disposing the disposer.
示例
声明堆栈的所有权
js
function consumeStack(stack) {
using newStack = stack.move(); // newStack now owns the disposers
console.log(stack.disposed); // true
console.log(newStack.disposed); // false
// newStack is disposed here immediately before the function exits
}
const stack = new DisposableStack();
console.log(stack.disposed); // false
consumeStack(stack);
console.log(stack.disposed); // true
允许资源在两个代码路径中被处置
move()
的主要用例是当你有一个或多个资源,这些资源可以立即被处置,也可以被保留以备将来使用。在这种情况下,你可以将资源放入 DisposableStack
,然后在需要将资源保留以备将来使用时调用 move()
。
js
class PluginHost {
#disposed = false;
#disposables;
#channel;
#socket;
constructor() {
// Create a DisposableStack that is disposed when the constructor exits.
// If construction succeeds, we move everything out of `disposer` and into
// `#disposables` to be disposed later.
using disposer = new DisposableStack();
// Create an IPC adapter around process.send/process.on("message").
// When disposed, it unsubscribes from process.on("message").
this.#channel = disposer.use(new NodeProcessIpcChannelAdapter(process));
// Create a pseudo-websocket that sends and receives messages over
// a NodeJS IPC channel.
this.#socket = disposer.use(new NodePluginHostIpcSocket(this.#channel));
// If we made it here, then there were no errors during construction and
// we can safely move the disposables out of `disposer` and into `#disposables`.
this.#disposables = disposer.move();
// If construction failed, then `disposer` would be disposed before reaching
// the line above. Event handlers would be removed, allowing `#channel` and
// `#socket` to be GC'd.
}
[Symbol.dispose]() {
if (this.#disposed) {
return;
}
this.#disposed = true;
// Put `this.#disposables` into a `using` variable, so it is automatically
// disposed when the function exits.
using disposables = this.#disposables;
// NOTE: we can free `#socket` and `#channel` here since they will be
// disposed by the call to `disposables[Symbol.dispose]()`, below.
// This isn't strictly a requirement for every disposable, but is
// good housekeeping since these objects will no longer be useable.
this.#socket = undefined;
this.#channel = undefined;
this.#disposables = undefined;
}
}
规范
规范 |
---|
ECMAScript 异步显式资源管理 # sec-disposablestack.prototype.move |
浏览器兼容性
加载中…