我正在执行以下过程,以便尝试并优化服务器上的速度和负载。然而,事情开始变得无序,我不知道为什么。这让我相信一些我不明白的事情。这是代码:
getInfo ( startIndex, endIndex ) { //starts with 0, 3 as the two params
var arr = globalArray.splice(startIndex, endIndex);
var tempThis = this;
this.function1( arr, function () {
this.function2( arr, function () {
if (end != tempThis.globalArray.length - 1) {
var newStart = endIndex;
var newEnd = endIndex + 3;
if (newEnd > tempThis.globalArray.length - 1) {
newEnd = tempThis.globalArray.length - 1;
}
console.log("about to recurse");
tempThis.getInfo(newStart, newEnd);
}
})
})
}
function1 ( list ) {
list.forEach( function ( thing ) {
httpCall( params, function ( data, error ) {
//logic
if(list.indexOf(thing) == list.length - 1) {
callback();
}
})
})
}
function2 ( list ) {
list.forEach( function ( thing ) {
httpCall( params, function ( data, error ) {
//logic
if(list.indexOf(thing) == list.length - 1) {
callback();
}
})
})
}
这个过程的目的是让一切顺序。所以,我有一个很大的globalList,我想做逻辑。我一次分解3并通过我的逻辑发送。它确实有功能1,然后(并且只有那时)当我发现我在迷你列表的最后一个索引时,我调用了回调,它应该转移到function2逻辑。然后,只有这样才能增加索引并递归。
我对回调的理解是它应该基本上使进程同步。但是,回调以不可预测的顺序被调用,并且通常被调用太多次。我觉得我在function1和2中的逻辑是合理的。
问题:我的理解错了吗?如果不是这个过程不是很好的做法?
答案 0 :(得分:2)
function1 / function2 forEach中的代码将以异步方式处理,因为HTTP调用是异步的。这意味着如果传递给函数的较小列表有3个项目,则会在不同时间触发并处理3个HTTP调用。无法保证呼叫将按照您发出请求的顺序完成,因此您将遇到3个呼叫中的最后一个呼叫在其他2个呼叫完成之前完成的情况,并且在其他两个呼叫完成之前将触发回叫完成。您可以尝试通过跟踪目前已处理的数量来解决该问题,而不是仅仅查看索引。
function processPart1(list, callback) {
let numProcessed = 0;
list.forEach(function (item) {
httpCall(params, function (data, error) {
//logic
numProcessed++;
if (numProcessed === list.length) {
callback();
}
});
});
}
通过这种传递回调并尝试管理使异步进程同步运行的方法会遇到的一个问题是,它可能难以读取,并且这样的错误可能会蔓延。切换到基于承诺的技术可以帮助解决这两个问题。像Q这样的Promise库可以帮助解决这两个问题。例如,Q有一个处理异步操作列表的方法,并且一旦完成所有操作就会工作(即Q.all)。
此外,被调用的代码一旦完成就不需要知道调用它的代码需要做什么。由于异步编程的本质,Promise似乎是解决问题的最佳实践之一。现在,许多库都包含基于promise的HTTP调用方法(即jQuery)。
使用像Q这样的库,你可以做类似以下的事情。这只是一个示例,向您展示如何使用promises来协调所有事情。
function getInfo(startIndex, endIndex) { //starts with 0, 3 as the two params
var arr = globalArray.splice(startIndex, endIndex);
var tempThis = this;
Q.all(arr.map(function (item) {
return processItemPart1(item));
}))
.then(function () { // this is called when all part 1 promises resolve
return Q.all(arr.map(function (item) {
return processItemPart2(item);
}));
})
.then(function () { // this is called when all part 2 promises resolve
if (end != tempThis.globalArray.length - 1) {
var newStart = endIndex;
var newEnd = endIndex + 3;
if (newEnd > tempThis.globalArray.length - 1) {
newEnd = tempThis.globalArray.length - 1;
}
console.log("about to recurse");
tempThis.getInfo(newStart, newEnd);
}
})
.fail(function () { // this is called when an error occurs
// do anything on error
})
.done();
}
function processItemPart1(item) {
// This is one way using the library to make the HTTP call
// promise-based.
return Q.Promise(function (resolve, reject) {
httpCall(params, function (data, error) {
if (error) {
// logic for error
reject(new Error(error));
return;
}
// logic for success
resolve();
});
});
}
function processItemPart2(item) {
// This is another way using the library to make the HTTP call
// promise-based.
let deferred = Q.defer();
httpCall(params, function (data, error) {
if (error) {
// logic for error
deferred.reject(new Error(error));
return;
}
// logic for success
deferred.resolve();
});
return deferred.promise;
}
function processItemPart3IfThereWasOne(item) {
// This is another way using the Q library with a library like jQuery
// whose ajax calls actually return a promise.
return Q($.ajax(params))
.then(function () {
// logic
});
}
<强>资源:强>
答案 1 :(得分:1)
我现在面临类似的问题。根据定义,回调是异步的,http客户端返回observables,它们被设计为异步管理数据。
我现在正在研究ngrx
,它可以通过管理&#34;流&#34;来解决这个问题。动作(又称 - 命令序列随时间变化),以便在数据所处的状态之间更加无缝地转换。