【发布时间】:2020-04-27 22:06:42
【问题描述】:
我使用来自asnyc framework 的eachOf 遍历js 数组,并在每次迭代中都有一个异步函数。如果调用callback 并且没有引发错误,则代码到达return 语句。我想知道为什么返回被忽略并且不会立即离开承诺菊花链。如果我在eachOf 函数周围包装另一个promise 并解析回调函数中的值,则第一级promise 将按预期完成。
这是为什么呢?回调函数中的返回不应该足以结束函数吗?
app1.js
const module1 = require('./module1');
const errorHandler = require('./error'); //implements custom error handler, e.g. log, mail, prowl, etc.
module1.getSomeVals()
.then(result => {
console.log('this is result:', result); //this returns undefined because the return in module1 not working
})
.catch(e => {
errorHandler.handle(e);
});
module1.js
const async = require('async'); //node module
const db = require('./db'); //custom db class
const module1 = {};
module1.getSomeVals= () => {
return new Promise(resolve => {
//some asyncronous function resolves values for next chain element, e.g. database stream
const resultFromSomeAsyncFunction = [
{
foo: 'foo1',
bar: 'bar1'
},
{
foo: 'foo2',
bar: 'bar2'
},
{
foo: 'foo3',
bar: 'bar3'
},
];
resolve(resultFromSomeAsyncFunction);
})
.then(results => {
let newResults = [];
async.eachOf(results, (result, index, callback) => {
return db.query("select * from names where foo = '" + result.foo + "' and bar = '" + result.foo)
.then(rows => {
newResults.push(rows);
console.log('this is rows:', rows);
callback(null); //doesn't need second parameter, because newResults defined above
})
.catch(e => {
callback(e); //throw e works as well
});
},
(err) => {
if (err)
throw err;
else {
console.log('this is newResults:', newResults); //this is the new result as expected.
return newResults; //this return doesn't exit the function as expected and the next log will be reached
}
});
console.log('this is newResults and shouldn\'t reached at all:', newResults); //this line will be reached, but should'nt
});
};
module.exports = module1;
app2.js
const module2 = require('./module2');
const errorHandler = require('./error'); //implements custom error handler, e.g. log, mail, prowl, etc.
module2.getSomeVals()
.then(result => {
console.log('this is result:', result); //this returns the expected newResults array because the wrapped promise resolves the newResults
})
.catch(e => {
errorHandler.handle(e);
});
module2.js
const async = require('async'); //node module
const db = require('./db'); //custom db class
const module2 = {};
module2.getSomeVals = () => {
return new Promise(resolve => {
//some asyncronous function resolves values for next chain element, e.g. database stream
const resultFromSomeAsyncFunction = [
{
foo: 'foo1',
bar: 'bar1'
},
{
foo: 'foo2',
bar: 'bar2'
},
{
foo: 'foo3',
bar: 'bar3'
},
];
resolve(resultFromSomeAsyncFunction);
})
.then(results => {
let newResults = [];
return new Promise(resolve => {
async.eachOf(results, (result, index, callback) => {
return db.query("select * from names where foo = '" + result.foo + "' and bar = '" + result.foo)
.then(rows => {
newResults.push(rows);
console.log('this is rows:', rows);
callback(null); //doesn't need second parameter, because newResults defined above
})
.catch(e => {
callback(e); //throw e works as well
});
},
(err) => {
if (err)
throw err;
else {
console.log('this is newResults:', newResults); //this is the new result as expected.
resolve(newResults); //this resolve exit the function as expected and the next log wont be reached
}
});
});
console.log('this is newResults and shouldn\'t reached at all:', newResults); //this line wont be reached as expected
});
};
module.exports = module2;
Module2 的代码风格很乱。我想在代码中有一个干净稳定的结构。
async eachOf 的文档说:
当所有迭代函数完成或发生错误时调用的回调。使用 (err) 调用。
返回:一个承诺,如果回调被省略
类型承诺
考虑到像resolve 这样的回调不再可用,我除了返回应该结束承诺之外。我想明白,为什么会有这样的行为。
【问题讨论】:
-
@T.J.Crowder 如果我在
module2.getSomeVals()app.js 中有一个自定义捕获处理程序? -
@T.J.Crowder 我的意思是自定义 errorHandler,而不是 catchHandler。我不想引起混乱。我更新了我的问题。谢谢!
-
更新后的代码将拒绝转换为履行,其值为
undefined。这通常是个坏主意。如果您要返回承诺链(就像您在这种情况下一样),请不要处理拒绝;让接收链的调用者处理错误。 -
@T.J.Crowder 非常感谢,但我不想浪费你的时间。你说的很清楚——我明白了。如果我拒绝一个错误,而该链中没有捕获,它将是未定义的。
throw是这样的,不是吗? -
好的。然后就好了。基本上,promise 的规则之一是:您必须要么处理错误,要么将 promise 链返回到可以处理的东西。您的代码(现在)在不返回链的情况下处理错误,所以没关系。如果它返回链,你不会想要
catch处理程序。
标签: javascript node.js asynchronous promise async.js