javascript - 在 Node 中正确批处理嵌套的 Promise

标签 javascript node.js asynchronous promise knex.js

我正在 Node 中运行 knex 种子,由于服务器的限制,需要对我的数据库进行批处理附加查询。我开始掌握 Promise 和 async/await 的窍门,但我很难让它在多个深度级别上工作(此时特别让我失望的是,它似乎以一种我不太理解的方式干扰批处理)。我的 seed 文件如下所示:

exports.seed = async function(knex) {
  const fs = require('fs');
  const _ = require('lodash');

  function get_event_id(location) {
    return knex('events')
      .where({location: location})
      .first()
      .then(result => { return result['id']; })
      .finally(() => { knex.destroy() })
  }

  function createImage(row, event_id) {
    return {
      name: row[4],
      event_id: event_id
    }
  };

  async function run_query(line) {
      let row = line.split(',');
      let event_id = await get_event_id(row[0]);
      return createImage(row, event_id);
  };

  async function run_batch(batch) {

      return Promise.all(batch.map(run_query));
  } 

  const file = fs.readFileSync('./data.csv');
  const lines = file.toString().replace(/[\r]/g, '').split('\n').slice(1,60); // skip csv header, then run first 59 lines

  const batches = _.chunk(lines, 30); // set batch size

  let images = await Promise.all(batches.map(run_batch));

  console.log(_.flatten(images).length);

};

我的数据库一次可以处理 30 个查询。如果我在定义 lines 的行上使用 .slice(1,30) 运行单个批处理,一切都会正确解析。但是使用上面的 60 运行会给我ER_TOO_MANY_USER_CONNECTIONS:用户已经拥有超过“max_user_connections”的事件连接

如果我将 run_batch 的内容更改为 return batch.map(run_query),则脚本完成,并且它返回正确的条目数(因此它似乎正确批处理)。但 promise 仍然悬而未决。我缺少什么,有没有更优雅的方法来做到这一点?

最佳答案

在这一行中:

let images = await Promise.all(batches.map(run_batch));

您正在尝试并行运行所有批处理,这完全破坏了您的分块。

您可以使用带有 await 的常规 for 循环,而不是 .map(),这样您就可以运行批处理,等待它完成,然后运行下一个批处理。

let allResults = [];
for (let batch of batches) {
     let images = await run_batch(batch);
     allResults.push(...images);
}
console.log(allResults);
<小时/>

仅供引用,您可能会受益于人们编写的任意数量的函数,这些函数用于处理同时运行的请求不超过 N 个的大型数组。这些不需要您手动将数据分成批处理。相反,它们会监视同时进行的请求数量,并启动您所需数量的请求,当一个请求完成后,它们会启动另一个请求,为您收集结果。

runN(fn, limit, cnt, options): Loop through an API on multiple requests

pMap(数组,fn,限制):Make several requests to an api that can only handle 20 at a time

rateLimitMap(array, requestsPerSec, maxInFlight, fn): Proper async method for max requests per second

mapConcurrent(数组,maxConcurrent,fn):Promise.all() consumes all my ram

Bluebird promise library 中还内置了执行此操作的功能。和 Async-promises library .

关于javascript - 在 Node 中正确批处理嵌套的 Promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59976352/

相关文章:

node.js - 如何使用 .map 正确创建 Promise.all 函数?

javascript - 在 Vue.js 中随机播放两个 json 文件的内容

javascript - 将 JavaScript 附加到 JIRA 中的所有页面

javascript - 有没有一个 jQuery 插件可以进行分步式演示?

node.js - 如何使用 Jest/ enzyme 模拟 multer 以使用 axios post mock call 上传文件

c++ - 跟进: Asynchronous off-screen query performance

javascript - 使用 javascript 显示选定复选框的列表

mysql - 如何记录由 sequelize ORM 执行的 sql 查询?

javascript - postman 中的响应数据有一些附加字符

ios - DispatchGroup 仅当方法被调用两次时才会退出