链接Promises(.animate和setTimeout之间的差异)

时间:2014-07-03 07:09:37

标签: javascript jquery html promise

我想问一下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);
});

所以我的问题是:为什么第一种情况正常,第二种情况不正常?我认为异步任务以相同的方式处理。我应该如何更改代码以正确链接任何函数(等待先前的函数执行)。

1 个答案:

答案 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/(需要内置承诺的浏览器)