如何使用promises强制执行特定的执行订单?

时间:2015-11-10 16:14:40

标签: javascript node.js promise

以下是程序代码:

jobQueueManager.addSource = (source) => {
    console.log('addSource', 'source', source);

    return new P(
        (resolve) => {
            connection.beginTransaction((errorTransaction) => {
                if (errorTransaction) {
                    throw new Error('Error starting a transaction.');
                }

                connection.query('SELECT `id` FROM `source` WHERE `country_code` = ? AND `nid` = ?', [
                        source.countryCode,
                        source.nid
                    ], (errorSelect, rows) => {
                    if (errorSelect) {
                        console.log('errorSelect', errorSelect);

                        throw new Error('Error selecting a source.');
                    }

                    // This should be able to find the row after the second time .addSource has been called
                    // with the same data. But because second "select" happens before the first query is
                    // commited, it does not.
                    console.log('select source', 'rows', rows);

                    if (rows.length === 0) {
                        connection.query('INSERT INTO `source` SET ?', {
                            country_code: source.countryCode,
                            nid: source.nid
                        }, (errorInsert, result) => {
                            if (errorInsert) {
                                throw new Error('Error inserting a source.');
                            }

                            console.log('insert source', 'source', source);

                            resolve(result.insertId);
                        });
                    } else {
                        resolve(rows[0].id);
                    }
                });
            });
        })
        .then((sourceId) => {
            return new P((resolve) => {
                connection.commit((errorCommit) => {
                    console.log('commit source');
                    if (errorCommit) {
                        throw new Error('Error committing a transaction.');
                    }

                    resolve({
                        id: sourceId,
                        ...source
                    });
                });
            });
        })
        .tap((sourceEntity) => {
            console.log('sourceEntity', sourceEntity);
        });
};

以下是执行程序的说明:

Promise
    .all([
        jobQueueManager
            .addSource({
                countryCode: 'uk',
                nid: 'foo'
            }),
        jobQueueManager
            .addSource({
                countryCode: 'uk',
                nid: 'foo'
            })
        ,
        jobQueueManager
            .addSource({
                countryCode: 'uk',
                nid: 'foo'
            })
    ]);

这是输出:

addSource source { countryCode: 'uk', nid: 'foo' }
addSource source { countryCode: 'uk', nid: 'foo' }
addSource source { countryCode: 'uk', nid: 'foo' }
select source rows []
select source rows []
select source rows []
insert source source { countryCode: 'uk', nid: 'foo' }
insert source source { countryCode: 'uk', nid: 'foo' }
insert source source { countryCode: 'uk', nid: 'foo' }
commit source
sourceEntity { id: 1, countryCode: 'uk', nid: 'foo' }
commit source
sourceEntity { id: 2, countryCode: 'uk', nid: 'foo' }
commit source
sourceEntity { id: 3, countryCode: 'uk', nid: 'foo' }

我希望执行顺序为:

  • 选择,插入;
  • 选择
  • 选择

但我得到了:

  • 选择
  • 选择
  • 选择
  • 插入件;
  • 插入件;
  • 插入件;

1 个答案:

答案 0 :(得分:0)

我设法做到这一点的唯一方法是使用执行队列,例如

jobQueueManager.addSource = (source) => {
    let newSource;

    newSource = P.all(jobQueueManager.addSource.executionQueue).then(() => {
        return new P(
            (resolve) => {
                // ...
            });
    });

    jobQueueManager.addSource.executionQueue.push(newSource);

    return newSource;
};

jobQueueManager.addSource.executionQueue = [];

这会产生预期的行为:

select source rows []
insert source source { countryCode: 'uk', nid: 'foo' }
commit source
sourceEntity { id: 1, countryCode: 'uk', nid: 'foo' }
select source rows [ RowDataPacket { id: 1 } ]
commit source
sourceEntity { id: 1, countryCode: 'uk', nid: 'foo' }
select source rows [ RowDataPacket { id: 1 } ]
commit source
sourceEntity { id: 1, countryCode: 'uk', nid: 'foo' }