Promise.withResolvers みたいな AsyncIterator.withResolvers がほしい

皆さまは Promise.withResolvers() は使っておられますでしょうか？

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers

new Promise() と違ってネストを浅くでき、また、 wrap しなくていいので こじんまりと使えるのが利点です。

で、で、でです。

# Promise.withResolvers みたいな AsyncIterator.withResolvers がほしい

本題 です。

Promise.withResolvers() だと resolve / reject / promise を生やしていましたが
AsyncIterator.withResolvers() だと resolve / reject / values / complete を生やして 外から操作できるようにするというニュアンスです。

つまりこんな感じのメソッドが欲しいという話です。

```js
(globalThis.AsyncIterator ??= {}).withResolvers ??=
/**
 * @template T
 */
function withResolvers() {
  let completed = false;
  const DONE = {};
  const resolvers = [withResolvers()];
  return { resolve, reject, complete, values: values() };
  /**
   * @param {T} result
   */
  function resolve(result) {
    const resolver = resolvers.at(-1);
    resolver?.resolve(result);
    if (result !== DONE)
      resolvers.push(withResolvers());
  }
  /**
   * @param {never} reason
   */
  function reject(reason) {
    const resolver = resolvers.at(-1);
    if (resolver) {
      resolver.reject(reason);
      complete();
    }
  }
  function complete() {
    resolve(DONE);
  }
  async function* values() {
    do {
      const resolver = resolvers[0];
      if (!resolver.status) await resolver.promise;
      if (resolver.status === "rejected") resolver.rethrow();
      if (resolver.status === "fulfilled") resolvers.shift();
      if (resolver.result === DONE) break;
      yield resolver.result;
    } while (resolvers.length > 0);
  }
  /**
   * @template T
   */
  function withResolvers() {
    const {
      promise,
      resolve: resolve_,
      reject: reject_,
    } = Promise.withResolvers();
    let status = undefined;
    let result = undefined;
    let reason = undefined;
    /**
     * @param {T} r 
     */
    function resolve(r) {
      if (status) return;
      status = "fulfilled";
      result = r;
      resolve_(r);
    }
    /**
     * @param {never} r 
     */
    function reject(r) {
      if (status) return;
      status = "rejected";
      reason = r;
      reject_(r);
    }
    return {
      /** @returns {"fulfilled"|"rejected"|undefined} */
      get status() {
        return status;
      },
      /** @returns {T} */
      get result() {
        return result;
      },
      rethrow() {
        throw reason;
      },
      promise,
      resolve,
      reject,
    };
  }
};
```

使い方としては次の様な感じです。


```js
const {resolve, values, complete} = AsyncIterator.withResolvers();
element1.addEventListener("click", resolve, {signal});
element2.addEventListener("click", resolve, {signal});
signal.addEventListener("abort", complete);

for await (const event of values) {
  console.log(event);
}
```

複数 もしくは 単数 の 連続したイベントを ループで処理したい という需要はあるのでは？と思います。（無い？

例えば window を別途開いてそちらの通信を連続して処理するとき

```js
const win = window.open(..., '_blank');
const {resolve, values, complete} = AsyncIterator.withResolvers();
win.addEventListener('message', ({data}) => resolve(data));

// #region window が閉じるのを監視
(async ()=> {
    while (!win.closed) {
        await new Promise((resolve) => setTimeout(resolve, 1000));
    }
    complete();
})();
// #dendregion

// #region entry point
for await (const data of values) {
    // doing... 
}
// #endregion
```


以上。

# 参考

[playground](https://livecodes.io/?x=id/ej627ckf773)