http - Angular 2 : Recursion with Callbacks and REST api calls

标签 http angular recursion callback synchronization

我正在执行以下过程,以尝试优化服务器的速度和负载。但是,事情开始变得乱七八糟,我不确定为什么。这让我相信发生了一些我不明白的事情。这是代码:

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 个并发送我的逻辑。它执行 function1 的事情,然后(并且只有那时)当我发现我在迷你列表的最后一个索引上时,我会回调回调,它应该移动到 function2 逻辑。然后并且只有到那时它才应该增加索引并递归。

我对回调的理解是它基本上应该使进程同步。但是,回调的调用顺序不可预测,而且调用次数通常过多。我觉得我在 function1 和 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();
            }
        });
    });
}

使用这种传递回调并尝试管理使异步进程同步运行的方法时,您会发现一个问题是它可能变得难以阅读,并且可能会潜入这样的错误。切换到基于 promise 的技术可以帮助解决这两个问题。像 Q 这样的 Promise 库具有帮助解决这两个问题的功能。例如,Q 有一个方法来处理异步操作列表并在所有操作完成后开始工作(即 Q.all)。

此外,被调用的代码不需要知道调用它的代码在完成后需要做什么。 Promises 似乎是解决由于异步编程的性质而出现的问题的最佳实践之一。许多库现在包含基于 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
    });
}

资源:

Q 库文档:https://github.com/kriskowal/q

关于http - Angular 2 : Recursion with Callbacks and REST api calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41624018/

相关文章:

django - Heroku 和 Django 出现 405 错误

javascript - Angularfire2 AngularFirestoreCollection 不发送集合中每个对象的键

angular - 在 Angular 4+ 中绑定(bind)到属性/函数与变量是不是很糟糕?

python - 斐波那契程序在第 40 个任期后挂起

python - Python 索引时的递归限制

c++ - C++中的递归

api - 在请求正确时获得 401 http 响应(有时)

html - 为什么这个 http 对话有 10 秒的延迟?

c# - 通过 Fiddler 向 asp.net mvc 操作发送 POST 请求

node.js - 由 : org. gradle.api.InvalidUserDataException 引起:无法添加任务 ':client:test',因为同名任务已存在