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

瀏覽器相容性

另見