我有一个for_users
函数,它从Web服务获取一组用户,在接收到的数组上执行传递函数f
,然后调用继续f_then
回调。
// Execute f on every user, then f_then.
function for_users(f, f_then)
{
// Get all users from the database, in user_array
db.get_all_users(function(user_array)
{
// Execute f on every user
user_array.forEach(f);
// Call continuation callback
f_then();
});
}
调用for_users
时,将异步函数作为f
参数传递,我希望所有f
回调在调用f_then
之前结束。这显然不会出现在当前代码中,因为user_array.forEach(f)
在开始下一次迭代之前不会等待f
完成。
以下是一个有问题的情况示例:
function example_usage()
{
var temp_credentials = [];
for_users(function(user)
{
// Get credentials is an asynchronous function that will
// call the passed callback after getting the credential from
// the database
database.get_credentials(user.ID, function(credential)
{
// ...
});
}, function()
{
// This do_something call is executed before all the callbacks
// have finished (potentially)
// temp_credentials could be empty here!
do_something(temp_credentials);
});
}
如何实施for_users
,如果f
是异步函数,只有在所有f_then
函数完成后才会调用f
?
但有时,传递的f
到for_users
不是异步的,上面的实现就足够了。有没有办法编写一个通用for_users
实现,它既可以用于异步和同步f
函数?
答案 0 :(得分:1)
你可以在f函数中添加下一个延续回调,如下所示:
Play App
然后您可以使用以下方法调用此函数:
function for_users(f, f_then) {
// Get all users from the database, in user_array
db.get_all_users(function(user_array) {
// Execute f on every user
(function recur(next) {
var user = user_array.shift();
if (user) {
f(user, function() {
recur(next);
});
} else {
// Call continuation callback
next();
}
})(f_then);
});
}
答案 1 :(得分:1)
这对你有用: -
function for_users(f, f_then) {
db.get_all_users(function(user_array) {
var promises = [];
user_array.forEach(function(user) {
promises.push(new Promise(function(resolve, reject) {
f(user);
resolve();
}));
});
if (f_then)
Promise.all(promises).then(f_then);
else
Promise.all(promises);
}
});
}
以下简单测试: -
function for_users(f, f_then) {
var users = [{ID: 1}, {ID: 2}, {ID: 3}];
var promises = [];
users.forEach(function(user) {
var promise = new Promise(function(resolve, reject) {
f(user);
resolve();
});
promises.push(promise);
})
if (f_then)
Promise.all(promises).then(f_then);
else
Promise.all(promises)
}
for_users(function(user) {
console.log(user.ID);
}, function() {
console.log('finshed')
})
答案 2 :(得分:0)
var getCredentials = function(step){
return function(user){
database.get_credentials(user.ID, function(credential) {
step(credential);
});
};
};
var allFinish = function(f){
return function(step) {
return function(arr){
var finished = 0;
var values = new Array(arr.length);
if(arr.length){
arr.forEach(function(el, i){
f(function(value){
if(finished === arr.length){
step(values);
} else {
values[i] = value;
finished++;
}
})(el);
});
} else {
step(values);
}
};
};
};
var forEachUser = function(doSomething){
db.get_all_users(allFinish(getCredentials)(doSomething));
}
然后你就可以做到:
forEachUser(function(tempCredentials){
//tempCredentials === allCredentials
});
可能有更好的方法来处理allFinish
中数组中插入的值的顺序。 allFinish
通过采用一个步骤并使用step函数调用它来工作,该函数将在所有调用完成时调用另一个step函数。我讨论了这些功能,但这并不是必需的。这只是一种便利。