循环并顺序执行代码

时间:2018-05-04 09:17:37

标签: rxjs knex.js bookshelf.js

我必须创建代码以1K行的批量插入行,但是当Bookshelf / Knex库使用Promises运行代码时,我有一些错误,我需要这个循环按顺序运行(仅在之后)完成第一个SQL,第二个应该开始)。

如何使用Promises(或Rx)执行此操作?

for (var x = 0; x < parser.getCount(); x++) {
    let row = parser.getRow(x);
    if (_.isEmpty(row) || _.isEmpty(row.ch) || _.isEmpty(row.location)) {
        break;
    }

    let locationData = breakDownLocation(row.location);

    middleSql += `(TRIM('${row.ch}'), TRIM('${row.color}'),TRIM('${moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').format('YYYY-MM-DD HH:mm:ss')}'), TRIM('${row.mvsDescription}'), ${locationData.position === '' || _.isUndefined(locationData.position) ? 'NULL' : locationData.position}, TRIM('${locationData.row}'), TRIM('${locationData.sector}'), ${convertStatusToInt(row.status)}, ${locationData.yardId}),`;
    itemsToInsert++;

    if (itemsToInsert >= 1000) {
        let sql = `${beginSql} ${middleSql.substring(0, middleSql.length - 1)} ${endSql}`;
        bookshelf.knex.raw(sql).then(r => {
            //console.log(r);
        })
        .catch(error => { 
            console.error(error);
        });

        middleSql = '';
        itemsToInsert = 0;
    }
}

2 个答案:

答案 0 :(得分:0)

您可以使用Rx重写代码

Observable.of(parser.getCount())
  .concatMap(i => {
    const row = parser.getRow(i);
    if (_.isEmpty(row) || _.isEmpty(row.ch) || _.isEmpty(row.location)) {
      return Observable.empty();
    }

    const locationData = breakDownLocation(row.location);
    return Observable.of(`(TRIM('${row.ch}'), TRIM('${row.color}'),TRIM('${moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').format('YYYY-MM-DD HH:mm:ss')}'), TRIM('${row.mvsDescription}'), ${locationData.position === '' || _.isUndefined(locationData.position) ? 'NULL' : locationData.position}, TRIM('${locationData.row}'), TRIM('${locationData.sector}'), ${convertStatusToInt(row.status)}, ${locationData.yardId}),`);
  })
  .bufferCount(1000)
  .concatMap(commands => {
    const middleSql = commands.join('');
    const sql = `${beginSql} ${middleSql.substring(0, middleSql.length - 1)} ${endSql}`;
    return bookshelf.knex.raw(sql);
  });

在上面的示例中,如果批处理中出现bookshelf.knex.raw错误,则不会提供错误处理,从而导致所有进一步处理停止。根据您的需要,您可以吞下错误或附加重试逻辑。

如果你能够使用await这也是一个有效的选项,可以让代码更容易阅读,因为使用Rx会将程序(for..each)流程移动到更多的FP中。

答案 1 :(得分:0)

之前我曾使用Array.prototype.reduce来完成此类事情。它看起来像这样。

const allDonePromise = someArray.reduce((previous, current) => {
  return previous.then(() => {
    return current.do()
  })
}, Promise.resolve())

我同意使用await可以帮助你以更易读的方式做到这一点。

另一种选择是使用递归并传回先前的承诺。像。的东西。

...
const doInserts = function(i = 0, promise = Promise.resolve()) {
  return promise.then(() => {
    ...
    if (itemsToInsert >= 1000) {
      ...
      return doInserts(i + 1, newSavesPromise)
    } else {
      return doInserts(i + 1, promise)
    }
  })
}