Как связать обещания Sequelize model.create (), чтобы они выполнялись по порядку? - PullRequest
2 голосов
/ 09 мая 2020

У меня интересная проблема с Sequelize, библиотекой Node ORM. Я использую sh, чтобы вставить эти данные в пустую таблицу:

[
      { 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 }
]

Как и следовало ожидать, в таблице fre sh им будут даны id значения 1, 2, 3 , et c в порядке возрастания. Итак, моя первая попытка написать это так:

  const writeToTable = (model, rows) => {
    let promises = rows.map((row) => model.create(row));
    return Promise.all(promises);
  }

Хорошо, вроде работает, но строки вставляются в непредсказуемом порядке, поскольку Promise.all выполняет обещания параллельно или, по крайней мере, выполняет нет гарантии, что они будут запускаться по порядку.

Итак, я снова попробовал это (используя некоторый код из этого ответа ):

  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;
  }

Похоже, что необходимо запускать элементы по порядку, но нет - запуск кода несколько раз может дать разные результаты. Odd!

Итак, я попробую следующее:

  const writeToTable = async (model, rows) => {
    let promises = rows.map((row) => model.create(row));

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

This is asyn c и не имеет возвращаемого значения, поэтому должен автоматически возвращать Promise, который разрешается после того, как все внутренние ожидаемые вызовы будут выполнены. решено. Но нет - я по-прежнему иногда получаю неправильно упорядоченные строки.

Какой метод я могу использовать, чтобы гарантировать, что мои вызовы выполняются по порядку? Я подозреваю, что Sequelize делает здесь кеширование / позднюю запись и попадает в рассол. Я рад слышать о подходах в Sequelize, которые передают весь массив, который нужно вставить, но это немного похоже на обман - интересно, хочу ли я понять , почему это не удается.

Я абсолютно уверен, что исходный массив правильный.

Может быть полезно знать, что эти вызовы выполняются в Jest для настройки тестовых данных перед вызовом службы и выполнением утверждений.

1 Ответ

1 голос
/ 09 мая 2020

После того, как 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 создает новое Promise немедленно для каждого элемента массива rows, поэтому все, что вы делаете после этого, не повлияет на порядок, в котором выполняются эти обещания. действие - то есть только после того, как предыдущее обещание завершило выполнение:

const writeToTable = (model, rows) => {
  for (const row of rows) {
    await model.create(row);
  }
}
...