demo · v134

Async transaction commit / rollback

The TC39 proposal’s top motivating case for the async half wasn’t about file handles — it was about database transactions, lock acquisitions, and async streams whose close / dispose is itself async. With await using, a transaction commits on the happy path and rolls back on throw, automatically, with no try / finally. Run both columns and watch the disposal logs.

probing await using / Symbol.asyncDispose…

Happy path vs error path

The transaction class

function openTx(name) {
  let committed = false;
  return {
    name,
    set(k, v) { … },
    commit() { committed = true; … },
    async [Symbol.asyncDispose]() {
      if (!committed) await this.rollback();
    },
    async rollback() { … },
  };
}

The caller

async function update(id, patch) {
  await using tx = openTx(`row-${id}`);
  await tx.set('name', patch.name);
  await tx.set('balance', patch.balance);
  await tx.commit();
} // if anything threw before commit(),
  // Symbol.asyncDispose runs rollback().

see also