Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensure sequence on post request using JavaScript

I am facing a problem when calling multiple post requests at the same time. I need them to be in sequence, but they get on the API in random order. How can I ensure a sequence order by using http method on JavaScript?

Here is an example of what I am doing:

for( var i = 0; i < result.length; i++ ) {
   $scope.update(result[i]);
}

$scope.update = function(results) {
    $http({
        method: 'POST',
        url: Config.serverUrl,
        data: JSON.stringify(results),
        headers: {'Content-Type': 'application/json'}
    }).then(function (response) {
        if ( response.data.status === "OK") {
            $scope.error = null;
            $scope.success = "Banco atualizado!";
        } else {
            $scope.error = response.data.message;
            $scope.success = null;
        }
        $scope.searchTimeout();
    }, function (response) {
        $scope.error = "Banco atualizado! (erro baddata)";
        $scope.success = null;
    });
};

UPDATE

Example working with two for loops and using promise as suggested by @TJCrowder:

$scope.myFunc = function(results) {
   return new Promise(function(resolve) {
      resolve($scope.update(results));
   });
};

var p = Promise.resolve();
for( var j = 0; j < result[3].length; j++ ){
    for( var i = 0; i < result[4].length; i++ ){
        p = p.then($scope.myFunc.bind($scope, results));
    }
}
like image 219
afjm Avatar asked Oct 29 '25 00:10

afjm


1 Answers

Add a return to your update so you return the promise, then convert the loop into a reduce call:

results.reduce(function(p, entry) {
    return p.then(function() { return $scope.update(entry); });
}, Promise.resolve());

That does the calls in series, waiting for the previous one to complete before starting the next, by creating a promise chain.

Or you can do it with just a for loop if you're doing this with a non-array list or similar:

var p = Promise.resolve();
for (var i = 0; i < results.length; ++i) {
    p = p.then($scope.update.bind($scope, results[i]));
}

We need the bind (or something similar) there because otherwise we run into the closures in loops problem. If you can rely on ES2015+ features, you can use let instead, which will let each closure close over its own i:

let p = Promise.resolve();
for (let i = 0; i < results.length; ++i) {
//   ^^^-- Important, `let` and `var` are quite different here
    p = p.then(() => $scope.update(results[i]));
}

There are more details about handling a collection of promises in series vs. in parallel in my answer to this other question, but I think it'd be a stretch to say this is a duplicate of that question.

like image 134
T.J. Crowder Avatar answered Oct 30 '25 15:10

T.J. Crowder