1

另一个应该很简单,但给我带来了麻烦。我正在尝试了解 jQuery 的 .Deferred() 和 .promise() 功能来延迟某些操作,直到递归函数完全完成。目前,我的代码类似于以下内容:

    function showText(setTarget, setMessage, setIndex, setInterval) {
        var defer = jQuery.Deferred();
        var doShowText = function (target, message, index, interval) {
            if (index < message.length) {
                $(target).append(message[index++]);
                setTimeout(function () { doShowText(target, message, index, interval); }, interval);
            }
            else {
                alert("Done!");
                defer.resolve();
            }
        };

        doShowText(setTarget, setMessage, setIndex, setInterval);
        return defer.promise();
    }

function startButtonClick() {
    displayElement($("#getElement"));
    showText($("#getElement > h1"), "This text will slowly write to the screen.", 0, 50).promise()
        .then(alert("Finished."));

}

当它运行时,“完成”警报(我试图推迟)在第一次执行递归脚本后运行,所以它会在只打印一个字母时出现(不是预期的结果)。但是,一旦打印了所有字母并且递归完成,“完成”警报就会正确显示,因此似乎我的 defer 变量直到那时才应该解决。谁能帮我找出为什么在这里提早调用“已完成”警报?任何帮助表示赞赏!

编辑:我意识到我不小心发布了一个稍微旧版本的代码。它已更新为正确的版本(运行时的行为相同)。

4

3 回答 3

2

startButtonClick函数中,您不需要调用.promise()的结果showText,因为您已经在showText. 接下来,then回调的参数应该是一个函数,现在您正在立即调用警报函数,而不是将其作为函数传递,这就是它立即显示的原因,所以只需将其包装在一个函数中:

function(){ alert("Finished."); }

这是一个带有代码的 jsfiddle:http: //jsfiddle.net/RnLXF/

于 2013-10-24T02:01:44.470 回答
2

发生这种情况是因为您实际上是在立即执行alert函数,而不是传递函数引用。

改为这样做:

.then(alert.bind(null, 'finished'));

或者

.then(function () {
    alert('finished');
});
于 2013-10-24T02:02:28.230 回答
1

这是一个把所有东西都包裹在一个漂亮的小物体中的小提琴:http: //jsfiddle.net/YVZKw/3/

正如plalxctcherry已经说过的,最大的问题是您的 .then 调用中缺少函数。

HTML

<a href='javascript:void(0)'>Start</a>

<div id='sampleElement'>
    <h1></h1>
</div>

JavaScript

$('a').on('click', function(){

    new ShowText(
        $("#sampleElement > h1"), 
        "I will slowly write text to the screen.",
        50
    )
    .done(function(){
        alert("Finished.")
    });
});

function ShowText(target, message, speed)
{
    me = this;
    me.target = target;
    me.message = message;
    me.index = 0;
    me.speed = speed;
    me.defer = new $.Deferred();

    me.interval = setInterval(function() {
        me.target.append(me.message[me.index++]);
        if (me.index > me.message.length) {
            clearInterval(me.interval);
            me.defer.resolve();
        }
    }, me.speed);

    return me.defer;
}
于 2013-10-24T02:20:11.620 回答