我想问一下javascript中的承诺是如何运作的。我很难理解由jQuery.animate和setTimeout组成的链的执行之间的区别。
如果我这样做:
var promise = new Promise(function(resolve, reject) {
resolve(
$("#something").animate({
width: 100
}, 1000);
)
});
promise.then(function(data) {
$("#something").animate({
height: 100
}, 1000);
});
然后第二个动画在第一个动画完成后开始(这是想要的行为)。另一方面,当我更改.then
(替换.animate
)时,例如setTimeout
然后它会在动画启动后立即执行(它不会等待动画结束)。
promise.then(function(data) {
setTimeout(function() {
console.log("timeout started");
}, 1000);
});
所以我的问题是:为什么第一种情况正常,第二种情况不正常?我认为异步任务以相同的方式处理。我应该如何更改代码以正确链接任何函数(等待先前的函数执行)。
答案 0 :(得分:7)
首先,jQuery将通过它的内置动画队列为您同步对象生成动画。你不需要使用任何承诺来做到这一点。
所以,如果你想让你的两个动画一个接一个,你就可以在不使用任何承诺的情况下做到这一点:
$("#something").animate({width: 100}, 1000).animate({height: 100}, 1000);
然后,如果你想使用jQuery动画的promises,你必须获得动画的承诺,如下所示:
$("#something").animate({width: 100}, 1000).promise();
然后您可以将该承诺与.then()
一起使用。
如果你想使用jQuery promises来控制动画,你可以这样做:
$("#something").animate({width: 100}, 1000).promise().then(function() {
$("#something").animate({height: 100}, 1000);
});
只需致电:
$("#something").animate({width: 100}, 1000);
原始代码中的返回一个jQuery对象,这不是一个promise本身可以使用的东西。
如果你真的想创建自己的promise对象并自己解决(jQuery动画不需要的东西,而且当你已经承诺可以使用的时候不推荐),你可以这样做您使用动画中的完成功能来解决您的承诺(使用您的编码风格):
var promise = new Promise(function(resolve, reject) {
$("#something").animate({width: 100}, 1000, resolve);
});
promise.then(function(data) {
console.log("timeout started");
setTimeout(function() {
console.log("timeout finished");
}, 1000);
});
所以,现在来解释你的代码中发生了什么。在您的第一个示例中,您的承诺逻辑根本不起作用(它几乎只是编码错误)。因此,两个动画都会被立即调用,但是因为jQuery将它们排队为你顺序运行,这就是你看到的行为。测序与你破碎的承诺逻辑无关。
然后,当您为第二个操作输入setTimeout()
时,jQuery不再为您排队,因为它本身不是jQuery动画,您的承诺逻辑仍然被破坏所以这两个操作同时执行。
如果你真的想要链接超时,那么你可以创建一个包含超时和承诺的包装器,它可以是可链接的:
function timer(t) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, t);
});
}
timer(1000).then(function() {
// do something here
return timer(1000);
}).then(function() {
// do something here
});
工作演示:http://jsfiddle.net/jfriend00/85Pr6/(需要内置承诺的浏览器)