使用 Promise.map 的每个承诺值作为下一个循环的输入
Using each promise value of Promise.map as input of the next loop
我已经做了一整天的研究,研究如何在 Promise.map
中获得每个承诺的结果,并在相同 Promise.map
的循环中将其用作下一次迭代的输入。我 严格地 需要执行此方法,因为我在 数据库操作 中使用此逻辑 必须是原子的 如果有任何承诺被拒绝,所有以前的交易都必须回滚。
注意: 我已经使用了 promise.each
并且它运行良好只是它不允许我关联各个承诺并回滚 all 如果一个失败。所以 Promise.map
似乎是最好的解决方案,当每个 promise 都被仔细地解决并且返回值时不会在下一个循环中导致 Error: Transaction query already complete
。这是 knex 的逻辑:
var obj={};
knex.transaction(function(trx) {
return Promise.map(array, function(item) {
return trx.insert(item).into('table')
.then(returnedFields => {
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
//[START EDIT: this responds to comment by @ Mikael Lepistö for clarity]
//update obj here to be used in next loop
//[END EDIT]
});
}, {concurrency: 1});
})
.then(function(inserts) {
console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
console.error(error);
})
看看这个:
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
您可以查看 async.js
图书馆 https://caolan.github.io/async/docs.html
您可以执行以下操作
knex.transaction(function(trx) {
return async.mapValuesSeries(array, (item) => {
return trx.insert(item).into('table')
.then(returnedFields => {
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
});
}, (error, inserts) => {
if (err) {
console.error(error);
}
console.log(inserts.length + 'Items saved.');
});
});
感谢所有发布 great/greater 见解的人。然而,事实证明 Promise.each
与 knex
配合得很好,我在循环期间错误地调用了 promises
的 then
内部的 commit
因此在后续循环的下一次事务尝试中导致 Error: Transaction query already complete
。 原因: 无需使用 knex 事务 context/block 调用 commit
,因为它会在该上下文中自动触发。
要在下面的回答中注明:
将 Knex
与 Promise.each
一起使用需要您在每个承诺的 then
块内听取可能的拒绝,并使用 try/catch
并且在某些情况下 明确拒绝否则后续promises/values将继续循环并且不能使数据库成为原子!!!
knex.transaction(function(trx) {
return Promise.map(array, function(item) {
return trx.insert(item).into('table')
.then(returnedFields => {
try{
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
/* START Testing a case of rejection */
if (array.indexOf(item) === 3) {
//uncomment the code below to test
//throw new Error('BreakException');
}
/* END */
}catch(err){
fail=true;
}
}).then(val => {
if (fail) {
trx.rollback()//you can ignore this as is automatically triggered here - tested
return Promise.reject(new Error('Rejected'))
}
return val
})
.catch(err => {
fail = true
trx.rollback()//you can ignore this as is automatically triggered here - tested
return Promise.reject(new Error('Rejected'))
});
});
})
.then(function(inserts) {
console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
console.error(error);
})
我已经做了一整天的研究,研究如何在 Promise.map
中获得每个承诺的结果,并在相同 Promise.map
的循环中将其用作下一次迭代的输入。我 严格地 需要执行此方法,因为我在 数据库操作 中使用此逻辑 必须是原子的 如果有任何承诺被拒绝,所有以前的交易都必须回滚。
注意: 我已经使用了 promise.each
并且它运行良好只是它不允许我关联各个承诺并回滚 all 如果一个失败。所以 Promise.map
似乎是最好的解决方案,当每个 promise 都被仔细地解决并且返回值时不会在下一个循环中导致 Error: Transaction query already complete
。这是 knex 的逻辑:
var obj={};
knex.transaction(function(trx) {
return Promise.map(array, function(item) {
return trx.insert(item).into('table')
.then(returnedFields => {
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
//[START EDIT: this responds to comment by @ Mikael Lepistö for clarity]
//update obj here to be used in next loop
//[END EDIT]
});
}, {concurrency: 1});
})
.then(function(inserts) {
console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
console.error(error);
})
看看这个:
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
您可以查看 async.js
图书馆 https://caolan.github.io/async/docs.html
您可以执行以下操作
knex.transaction(function(trx) {
return async.mapValuesSeries(array, (item) => {
return trx.insert(item).into('table')
.then(returnedFields => {
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
});
}, (error, inserts) => {
if (err) {
console.error(error);
}
console.log(inserts.length + 'Items saved.');
});
});
感谢所有发布 great/greater 见解的人。然而,事实证明 Promise.each
与 knex
配合得很好,我在循环期间错误地调用了 promises
的 then
内部的 commit
因此在后续循环的下一次事务尝试中导致 Error: Transaction query already complete
。 原因: 无需使用 knex 事务 context/block 调用 commit
,因为它会在该上下文中自动触发。
要在下面的回答中注明:
将 Knex
与 Promise.each
一起使用需要您在每个承诺的 then
块内听取可能的拒绝,并使用 try/catch
并且在某些情况下 明确拒绝否则后续promises/values将继续循环并且不能使数据库成为原子!!!
knex.transaction(function(trx) {
return Promise.map(array, function(item) {
return trx.insert(item).into('table')
.then(returnedFields => {
try{
//do some validation/operation and return the result or the returnedFields themselves as input in the next loop.
/* START Testing a case of rejection */
if (array.indexOf(item) === 3) {
//uncomment the code below to test
//throw new Error('BreakException');
}
/* END */
}catch(err){
fail=true;
}
}).then(val => {
if (fail) {
trx.rollback()//you can ignore this as is automatically triggered here - tested
return Promise.reject(new Error('Rejected'))
}
return val
})
.catch(err => {
fail = true
trx.rollback()//you can ignore this as is automatically triggered here - tested
return Promise.reject(new Error('Rejected'))
});
});
})
.then(function(inserts) {
console.log(inserts.length + 'Items saved.');
})
.catch(function(error) {
console.error(error);
})