我想让函数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个函数调用顺序发生。
好了,虽然至少还有两种选择,但你真正想要的东西已经变得更清楚了(基于你最近对澄清问题的评论)。
对于这样的操作,您可能希望利用许多承诺特性:
- jQuery的Ajax调用已经返回一个承诺,所以你可以直接使用这些
- 要序列化操作,只需将多个promise操作链接在一起
- 为了使异步操作正确序列化,你可以从
.then()
处理程序返回一个承诺,并且只有当所有链接的承诺都解决时,主承诺才会解决(有点像内置的$.when()
,而不必显式调用$.when()
)。 - 你可以将任意多的操作链在一起,并且主承诺会告诉你它们何时完成。
- 如果您从
A()
和B()
返回承诺,那么这些函数的调用者可以监控何时使用承诺方法完成,然后让您将A().then(B)
链接到这两个序列。 - 当你用链接对操作进行排序时,先验方法解析的数据作为
.then()
处理函数的第一个参数传递给链中的下一个.then()
处理函数,所以如果你需要下一个操作的先验数据,它就在那里。
因此,有了所有这些功能,只需在代码周围放置正确的支架来实现您想要的确切排序。这里有两个不同的选项:
选项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操作进行排序非常强大,您甚至可以对循环中的操作这样做。
像这样应该可以工作
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);
});
}
注意使用一个数组来保存承诺,然后使用$.when
和apply()
在循环中的所有ajax请求完成时触发一个回调。
假设假设…
让我们假设:
- 每个
get
的url都与其对应的post
的url相同 - 每个get-post对的url应该不同
- 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将需要更广泛的修改
我们可以使用jquery Deferred Object以我们的方式调用我们的choice函数。
很简单,让我们看看成功运行的例子:
<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>
没有额外工作的Javascript是单线程的。这意味着函数不能同时执行。但问题是,$.get()和$.post()调用是异步的。这意味着只要请求的数据到达您的客户机,它们就会执行。(先到先得)
一个解决方案是在所有结果A到达后执行函数B,或者保留所有结果并立即处理所有数据,然后运行update_dropdown()
。