【问题标题】:Raising function * into async function *?将函数 * 提升为异步函数 *?
【发布时间】:2018-05-29 18:34:08
【问题描述】:

假设我有一个函数,它接受一个生成器并返回第一个 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++;
  }
};

这样的用法:

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

for (const x of take(10, evens())) {
  console.log(x);
}

现在假设evens 也是async(有关设置,请参见this answer):

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

这当然不适用于take

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

main().catch(e => console.error(e));

现在,我可以定义一个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));

... 但是太麻烦了!

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

【问题讨论】:

标签: javascript async-await generator babeljs ecmascript-next


【解决方案1】:

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

没有。异步和同步发电机太不同了。您将需要两个不同的 take 函数实现,这是没有办法的。

但是,您可以动态选择要选择的一个:

async function* takeAsync(asyncIterable) { … }
function* takeSync(iterable) { … }

function take(obj) {
    if (typeof obj[Symbol.asyncIterator] == "function") return takeAsync(obj);
    if (typeof obj[Symbol.iterator] == "function") return takeSync(obj);
    throw new TypeError("not an iterable object");
}

通常不可能编写像asyncify(takeSync)(10, evensAsync()) 一样使用的函数asyncify。一个人可能能够一起破解适用于takeSyncmapSync 的东西,依赖于它们每个输入项只输出一个项目这一事实,但它会非常脆弱并且不适用于filter 等其他迭代函数.

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

function taker(n) {
  return {
    done: n > 0,
    *step(element) { /* if (n > 0) */ yield element; return taker(n-1); },
    result: null
  }
}
function mapper(fn) {
  return {
    done: false,
    *step(element) { yield fn(element); return this; }
    result: null
  }
}

function makeIterator(t) {
  return function*(iterable) {
    for (let element of iterable) {
      t = yield* t.step(element);
      if (t.done) break;
    }
    return t.result;
  };
}
function makeAsyncIterator(t) {
  return async function*(asyncIterable) {
    for await (let element of asyncIterable) {
      t = yield* t.step(element);
      if (t.done) break;
    }
    return t.result;
  };
}

(它无​​耻地撕掉了transducer concept - 也没有经过任何测试)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    相关资源
    最近更新 更多