Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/437.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何成批(大小相同的块)消费iterable?_Javascript_Ecmascript 6_Generator - Fatal编程技术网

Javascript 如何成批(大小相同的块)消费iterable?

Javascript 如何成批(大小相同的块)消费iterable?,javascript,ecmascript-6,generator,Javascript,Ecmascript 6,Generator,我经常在Python中使用。自具有迭代器和生成器函数的ES6以来,JavaScript中是否有其他替代方案?我必须为自己编写一个,我在这里与其他人分享,以便在这里轻松找到: // subsequently yield iterators of given `size` // these have to be fully consumed function* batches(iterable, size) { const it = iterable[Symbol.iterator]();

我经常在Python中使用。自具有迭代器和生成器函数的ES6以来,JavaScript中是否有其他替代方案?

我必须为自己编写一个,我在这里与其他人分享,以便在这里轻松找到:

// subsequently yield iterators of given `size`
// these have to be fully consumed
function* batches(iterable, size) {
  const it = iterable[Symbol.iterator]();
  while (true) {
    // this is for the case when batch ends at the end of iterable
    // (we don't want to yield empty batch)
    let {value, done} = it.next();
    if (done) return value;

    yield function*() {
      yield value;
      for (let curr = 1; curr < size; curr++) {
        ({value, done} = it.next());
        if (done) return;

        yield value;
      }
    }();
    if (done) return value;
  }
}

它生成生成器,而不是数组。在再次调用下一批之前,您必须完全消耗每批产品。

来这里查看其他人的建议。这是我在看这篇文章之前用TypeScript写的版本

async function* batch<T>(iterable: AsyncIterableIterator<T>, batchSize: number) {
  let items: T[] = [];
  for await (const item of iterable) {
    items.push(item);
    if (items.length >= batchSize) {
      yield items;
      items = []
    }
  }
  if (items.length !== 0) {
    yield items;
  }
}
这允许您按如下所示批量使用iterable

async function doYourThing<T>(iterable: AsyncIterableIterator<T>) {
  const itemsPerBatch = 5
  const batchedIterable = batch<T>(iterable, itemsPerBatch)
  for await (const items of batchedIterable) {
    await someOperation(items)
  }
}
在我的例子中,这使我能够更轻松地在Mongo中使用bulkOps,如下所示

import { MongoClient, ObjectID } from 'mongodb';
import { batch } from './batch';

const config = {
  mongoUri: 'mongodb://localhost:27017/test?replicaSet=rs0',
};

interface Doc {
  readonly _id: ObjectID;
  readonly test: number;
}

async function main() {
  const client = await MongoClient.connect(config.mongoUri);
  const db = client.db('test');
  const coll = db.collection<Doc>('test');
  await coll.deleteMany({});
  console.log('Deleted test docs');

  const testDocs = new Array(4).fill(null).map(() => ({ test: 1 }));
  await coll.insertMany(testDocs);
  console.log('Inserted test docs');

  const cursor = coll.find().batchSize(5);
  for await (const docs of batch<Doc>(cursor as any, 5)) {
    const bulkOp = coll.initializeUnorderedBulkOp();
    docs.forEach((doc) => {
      bulkOp.find({ _id: doc._id }).updateOne({ test: 2 });
    });
    console.log('Updating', docs.length, 'test docs');
    await bulkOp.execute();
  }
  console.log('Updated test docs');
}

main()
  .catch(console.error)
  .then(() => process.exit());

我希望您不介意我的编辑,它使最终值总是从外部迭代器发出。如果您不喜欢,请随意回滚。谢谢,我更喜欢您的版本。。我没有足够的距离进行最后的清理;我非常喜欢你的解决方案,因为它是通用的。不过,我建议将使用示例减少到两行或三行,以便更容易看到好处。@Sebastian这是一个很好的建议。更新。