javascript - 如何链接 Sequelize model.create() promise 以便它们按顺序执行?

标签 javascript node.js sequelize.js

我对 Node ORM 库 Sequelize 有一个有趣的问题。我希望将此数据插入到一个空表中:

[
      { title: 'Expenditure 1', amount: 100 },
      { title: 'Expenditure 2', amount: 200 },
      { title: 'Expenditure 3', amount: 300 },
      { title: 'Expenditure 4', amount: 400 },
      { title: 'Expenditure 5', amount: 500 },
      { title: 'Expenditure 6', amount: 600 },
      { title: 'Expenditure 7', amount: 700 },
      { title: 'Expenditure 8', amount: 800 },
      { title: 'Expenditure 9', amount: 900 },
      { title: 'Expenditure 10', amount: 1000 },
      { title: 'Expenditure 11', amount: 1100 },
      { title: 'Expenditure 12', amount: 1200 },
      { title: 'Expenditure 13', amount: 1300 },
      { title: 'Expenditure 14', amount: 1400 },
      { title: 'Expenditure 15', amount: 1500 },
      { title: 'Expenditure 16', amount: 1600 },
      { title: 'Expenditure 17', amount: 1700 },
      { title: 'Expenditure 18', amount: 1800 },
      { title: 'Expenditure 19', amount: 1900 },
      { title: 'Expenditure 20', amount: 2000 }
]

正如人们所料,在一个新表中,这些将被赋予 id 值 1、2、3 等,按升序排列。所以我第一次尝试写这些是这样的:
  const writeToTable = (model, rows) => {
    let promises = rows.map((row) => model.create(row));
    return Promise.all(promises);
  }

好吧,它有点工作,但行以不可预测的顺序插入,因为 Promise.all 并行运行 promise ,或者至少不保证按顺序运行它们。

所以我接下来尝试了这个(使用一些代码 from this answer ):
  const writeToTable = (model, rows) => {
    let promises = rows.map((row) => model.create(row));
    let chain;

    for (let i in promises) {
       if (chain) chain = chain.then(() => promises[i]);
       if (!chain) chain = promises[0];
    }

    return chain;
  }

看起来它必须按顺序运行项目,但不是 - 多次运行代码会产生不同的结果。奇怪的!

所以我接下来试试这个:
  const writeToTable = async (model, rows) => {
    let promises = rows.map((row) => model.create(row));

    for (let promise of promises) {
       await promise;
    }
  };

这是异步的,没有返回值,所以应该自动返回一个 Promise,一旦所有内部等待的调用都解决了就解决了。但是,不 - 我仍然偶尔会得到错误排序的行。

我可以使用什么技术来确保我的调用按顺序执行?我怀疑 Sequelize 在这里做了一些缓存/后期写入,并让自己陷入困境。我很高兴听到 Sequelize 中的方法可以将整个数组插入,但这感觉有点像作弊 - 我想知道我是否想了解为什么会失败。

我绝对确定源数组是正确的。

在调用服务和运行断言之前,了解这些调用是在 Jest 中进行以设置测试数据可能会有所帮助。

最佳答案

一旦 Promise 被创建,无论 Promise 的解析如何等待,它里面的操作都会运行到最后。例如:

const prom1 = makeProm1();
const prom2 = makeProm2();

在这一点上,Promises 已经开始,并且会做任何他们应该做的事情(并行),即使你稍后单独 await 它们:
await prom1;
await prom2;

const makeProm = num => new Promise(
  resolve => setTimeout(
    () => {
      console.log(num + ' resolving');
      resolve();
    },
    Math.random() * 1000
  )
);

(async () => {
  const prom1 = makeProm(1);
  const prom2 = makeProm(2);
  await prom1;
  await prom2;
  console.log('Done');
})();


这就是你的每个片段正在做的 - .map 立即为 rows 数组的每个项目创建一个新的 Promise,所以无论你之后做什么都不会影响这些 Promise 解析的顺序。

您需要更改一些内容,以便仅在您准备好开始执行 Promise 时才创建 Promise - 也就是说,仅在前一个 Promise 完成执行之后:
const writeToTable = (model, rows) => {
  for (const row of rows) {
    await model.create(row);
  }
}

关于javascript - 如何链接 Sequelize model.create() promise 以便它们按顺序执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61700176/

相关文章:

javascript - 如何在 JS 文件中获取永久的原始 Github 链接?

node.js - 如何在 Cloud Run 上部署 Typescript 项目

javascript - Sequelize Foreach 循环在更新数据之前发送响应

javascript - javascript回调和匿名函数的范围是什么?

node.js - 关于nodejs推送数据到浏览器开源框架

javascript - 如何创建一个 sequelize 事务来保存深度嵌套的对象

node.js - 当需要检查 jsonb 列中是否存在某个键时,如何使用 Sequelize 中的 queryInterface.bulkUpdate?

javascript - 如何启用禁用的输入字段?

javascript - 如何在版本号上使用 Javascript 数学

javascript - 两个对象之间的差异并添加缺失值