将功能*提升为异步功能*?

sdg*_*sdh 11 javascript generator async-await babeljs ecmascript-next

假设我有一个函数接受生成器并返回第一个n元素的另一个生成器:

const take = function * (n, xs) {
  console.assert(n >= 0);
  let i = 0;
  for (const x of xs) {
    if (i == n) {
      break;
    }
    yield x;
    i++;
  }
};
Run Code Online (Sandbox Code Playgroud)

用法如下:

const evens = function * () {
  let i = 0;
  while (true) {
    yield i;
    i += 2;
  }
};

for (const x of take(10, evens())) {
  console.log(x);
}
Run Code Online (Sandbox Code Playgroud)

现在想象一下,evens也是async(见这个答案的设置):

const evensAsync = async function * () {
  let i = 0;
  while (true) {
    yield i;
    i += 2;
  }
};
Run Code Online (Sandbox Code Playgroud)

当然,这不适用于take:

const main = async () => {
  for await (const x of take(10, evensAsync())) {
    console.log(x);
  }
};

main().catch(e => console.error(e));
Run Code Online (Sandbox Code Playgroud)

现在,我可以定义一个take变体async:

const takeAsync = async function * (n, xs) {
  console.assert(n >= 0);
  let i = 0;
  for await (const x of xs) {
    if (i == n) {
      break;
    }
    yield x;
    i++;
  }
};

const main = async () => {
  for await (const x of takeAsync(10, evensAsync())) {
    console.log(x);
  }
};

main().catch(e => console.error(e));
Run Code Online (Sandbox Code Playgroud)

...... 但是麻烦啊!

有没有办法在JavaScript中自动"异步"生成器函数?

Ber*_*rgi 1

\n

有没有办法在 JavaScript 中自动“异步”生成器函数?

\n
\n\n

不。异步和同步发电机实在是太不同了。您将需要两种不同的实现take,没有办法解决它。

\n\n

不过,您可以动态选择要选择哪一个:

\n\n
async function* takeAsync(asyncIterable) { \xe2\x80\xa6 }\nfunction* takeSync(iterable) { \xe2\x80\xa6 }\n\nfunction take(obj) {\n    if (typeof obj[Symbol.asyncIterator] == "function") return takeAsync(obj);\n    if (typeof obj[Symbol.iterator] == "function") return takeSync(obj);\n    throw new TypeError("not an iterable object");\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

一般来说不可能编写一个asyncify可以像asyncify(takeSync)(10, evensAsync()). 人们也许能够将一些适用于takeSync和 的东西组合在一起mapSync,依赖于它们为每个输入项精确输出一项的事实,但它会非常脆弱,并且不适用于其他迭代函数,例如filter

\n\n

也就是说,当然可以概括并提供抽象。

\n\n
function taker(n) {\n  return {\n    done: n > 0,\n    *step(element) { /* if (n > 0) */ yield element; return taker(n-1); },\n    result: null\n  }\n}\nfunction mapper(fn) {\n  return {\n    done: false,\n    *step(element) { yield fn(element); return this; }\n    result: null\n  }\n}\n\nfunction makeIterator(t) {\n  return function*(iterable) {\n    for (let element of iterable) {\n      t = yield* t.step(element);\n      if (t.done) break;\n    }\n    return t.result;\n  };\n}\nfunction makeAsyncIterator(t) {\n  return async function*(asyncIterable) {\n    for await (let element of asyncIterable) {\n      t = yield* t.step(element);\n      if (t.done) break;\n    }\n    return t.result;\n  };\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

(它无耻地剥夺了换能器的概念- 也没有进行任何测试)

\n