javascript中的顺序函数调用

时间:2014-05-04 00:10:49

标签: javascript jquery object promise deferred

我希望函数A完成执行,并且只有在函数B开始执行之后才能执行。当我调用函数A然后调用函数B时,它们似乎都在同时执行。在函数B完成后,我想调用第三个函数update_dropdown()。

我的代码如下所示:

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();
    });
}

请告诉我如何按顺序进行这3个函数调用。

5 个答案:

答案 0 :(得分:4)

好的,它可以更清楚地了解您的实际需求(根据您最近的评论来解决澄清问题),但仍然至少有两个选项可以打开。

对于这样的操作,您可能希望利用许多承诺功能:

  1. jQuery的Ajax调用已经返回一个承诺,所以你可以直接使用它们
  2. 要序列化操作,您可以将多个承诺操作链接在一起
  3. 要使异步操作正确序列化,您可以从.then()处理程序返回一个promise,只有当所有链接的promise都已解决时,master promise才会解析(没有内置$.when()的类型必须明确调用$.when())。
  4. 您可以根据需要将多个操作链接在一起,主承诺会告诉您何时完成这些操作。
  5. 如果你从A()B()返回promises,那么这些函数的调用者可以监视完成promise方法的时间,然后让你链接A().then(B)来排序这两个
  6. 当您使用链接对操作进行排序时,先前的方法解析数据将作为.then()处理程序函数的第一个参数传递给链中的下一个.then()处理程序函数,因此如果您需要先前的数据对于下一个操作,它就在那里使用。
  7. 因此,利用所有这些功能,只需在代码周围放置正确的脚手架即可实现您想要的精确顺序。以下是两种不同的选择:


    选项1:如果要序列化A()中的所有内容,以便所有10个请求以串行方式发生(下一个请求只在前一个请求完成时继续),那么可能看起来像这样:

    // 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);
    

    选项2:如果您希望A()中的5对请求并行运行,只有A()的最后一部分等待5对请求完成后,它可能看起来像这样:

    // 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);
    

    这些使用的概念是,如果从.then()处理函数返回一个promise,那么它会将多个异步操作链接在一起,并且只有在解析了所有链接操作后才能解析主promise。这对于对多个ajax操作进行排序非常强大,你甚至可以像你一样在循环中进行操作。

答案 1 :(得分:3)

这样的事情应该有效

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);
    });

}

注意使用数组来保留promises,然后使用$.whenapply()在循环中的所有ajax请求完成时触发回调。

答案 2 :(得分:1)

假设假设......

我们假设:

  • 每个get的网址与其对应的post
  • 的网址相同
  • 每个get-post对的网址应该有所不同
  • A中的五个get-post对可以并行发生,我们对返回的数据不感兴趣

首先,实用功能:

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

然后A和B,两者都调用实用程序:

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

最后是一个调用A和B的表达式:

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

如果假设1和2不正确,调整此代码应该相当简单。

如果假设3不正确,那么A将需要更广泛的修改。

答案 3 :(得分:0)

我们可以使用jquery Deferred Object以我们的方式调用我们的选择函数。

这很简单,让我们看看成功运行的例子:

<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>

答案 4 :(得分:-1)

没有额外工作的Javascript是单线程的。这意味着功能无法同时执行。但问题是$ .get()和$ .post()调用是异步的。这意味着只要请求的数据到达您的客户端,它们就会被执行。 (先到先得)

解决方案是在所有结果ob A到达后执行功能B,或者阻止所有结果并立即处理所有数据然后运行update_dropdown()