Sequential function calls in javascript

ぃ、小莉子 提交于 2019-12-19 04:10:09

问题


I want function A to finish execution and only after that function B should start executing. When I call function A and then function B, it seems both are executing simultaneously. And after function B completes, I want to call a third function update_dropdown().

My code looks like this:

function A {
    for (var i = 0; i < 5; i++) {
        var promise = $.get(url+i);
        $.when(promise).then(function () {
            $.post(url);
        });
    }
}
function B {
    var x = $.get(url);
    var promise = $.post(url+x);
    $.when(promise0).then(function () {
        update_dropdown();
    });
}

Please can you tell me how I can make these 3 function calls happen sequentially.


回答1:


OK, it's getting a little bit clearer what you actually want (based on your recent comments to address clarifying questions) though there are still at least two options open.

For an operation like this, you probably want to take advantage of a number of promise features:

  1. jQuery's Ajax calls already return a promise so you can just use those directly
  2. To serialize operations, you can just chain multiple promise operations together
  3. To make async operations serialize properly, you can return a promise from a .then() handler and the master promise will resolve only when all the chained promises have resolved (kind of a built-in $.when() without having to explicitly call $.when()).
  4. You can chain as many operations together as you want and the master promise will tell you when they are all done.
  5. If you return promises from both A() and B(), then the callers of those functions can monitor when they are done with promise methods which then lets you chain A().then(B) to sequence those two.
  6. When you sequence operations with chaining, the prior methods resolve data is passed to the next .then() handler function in the chain as the first argument to the .then() handler function so if you need the prior data for the next operation, it is right there to use.

So, with all those capabilities, it's just a matter of putting the right scaffolding around the code to implement the exact sequencing you want. Here are two different options:


Option 1: If you want to serialize everything in A() so that all 10 requests happen in serial fashion (the next one proceeds only when the prior one is done), then it could look like this:

// serialize all requests
function A() {
    var p = $.get(url).then(function(data) {return $.post(url)});
    for (var i = 1; i < 5; i++) {
        // chain four more pairs of requests onto the original promise
        p = p.then(function() {return $.get(url)})
             .then(function(data) {return $.post(url)});
    }
    // return the promise so callers can monitor when A() is done
    return p;
}


function B() {
    // sequence these three operations one after the other
    return ($.get(url)
       .then(function(data) {return $.post(url + x)})
       .then(update_dropdown)
    );
}

// run them both, one after the other
A().then(B);

Option 2: If you want the 5 pairs of requests in A() to run in parallel, with only the last part of A() waiting until the 5 pairs of requests are done, then it could look like this:

// parallelize pairs of requests
function A() {
    var promises = [];
    for (var i = 0; i < 5; i++) {
        // execute 5 pairs of requests where each pair is serialized in itself
        promises.push($.get(url).then(function(data) {return $.post(url)}));
    }
    // return a promise that resolves only when all the other promises are done
    return $.when.apply($, promises);
}

function B() {
    // sequence these three operations one after the other
    return ($.get(url)
       .then(function(data) {return $.post(url + x)})
       .then(update_dropdown)
    );
}

// run them both, one after the other
A().then(B);

These use the concept that if you return a promise from a .then() handler function, then it will chain multiple async operations together and the master promise is only resolved when all the chained operations are resolved. This is very powerful for sequencing multiple ajax operations and you can even do it for operations in a loop like you have.




回答2:


Something like this should work

function A {
    var xhr = [];

    for (var i = 0; i < 5; i++) {
        xhr.push( $.get(url) );
    }

    $.when.apply($, xhr).then(B);
}

function B {

    $.get(url).done(function(x) {
        $.post(url + x).done(update_dropdown);
    });

}

Note the use of an array to keep the promises in, then using $.when with apply() to fire a callback when all the ajax requests in the loop has finished.




回答3:


Assumptions assumptions ...

Let's assume that :

  • the url for every get is the same as that for its corresponding post
  • the urls for each get-post pair should vary
  • the five get-post pairs in A can occur in parallel and we are not interested in the returned data

First, a utility function :

function getThenPost(url, appendToURL) {
    return $.get(url).then(function(x) {
        return (appendToURL) ? $.post(url + x) : $.post(url);
    });
}

then A and B, both of which call the utility :

function A(urls) {
    return $.when.apply(null, urls.map(function(url) {
        return getThenPost(url, false);
    }));
}
function B(url) {
    return getThenPost(url, true);
}

and finally an expression that calls A and B :

A(['/path/0', '/path/1', '/path/2', '/path/3', '/path/4']).then(function() {
    B('/path/5');
}).then(update_dropdown);

It should be reasonably simple to adjust this code if assumptions 1 and 2 are incorrect.

If assumption 3 is incorrect then A will require more extensive modification.




回答4:


We can call our choice function in our way using jquery Deferred Object.

It is very simple let see successfully run example:

<body>
<script
    src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">

// I want to call function in order of  f1,f2,f3,f4 every time when i will execute this html page.

    promise = f1().then(f2).then(f3).then(f4); // Add handlers to be called when the Deferred object is resolved, rejected, or still in progress.

    function f1() {
        var d = $.Deferred();

        setTimeout(function() {
            // our code here....
            alert("1");
            console.log("1");
            d.resolve(); // resolve() :Resolve a Deferred object and call any doneCallbacks with the given args.
        },1000); // You set some time for each method.
        return d.promise(); //promise(): Return a Deferred’s Promise object.

    }
    function f2() {
        var d = $.Deferred();

        setTimeout(function() {
            alert("2");
            console.log("2");
            d.resolve();
        },1000);
        return d.promise();
    }
    function f4() {
        var d = $.Deferred();

        setTimeout(function() {
            alert("4");
            console.log("4");
            d.resolve();
        },1000);
        return d.promise();
    }
    function f3() {
        var d = $.Deferred();

        setTimeout(function() {
            alert("3");
            console.log("3");
            d.resolve();
        },1000);
        return d.promise();
    }


</script>




回答5:


Javascript without extra work is single threaded. that means functions are not able to be executed simultaneously. but the problem is that the $.get() and $.post() calls are asynchronous. that means they are executed whenever the requested data arrives your client. (first come first serve)

an solution would be to execute function B after all the results ob A arrived, or to hold back all results and handle all data at once then run update_dropdown().



来源:https://stackoverflow.com/questions/23451163/sequential-function-calls-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!