2013-10-24 60 views
1

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

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.")); 

} 

在运行此,“完成”警报(这我试图推迟)运行递归脚本的第一执行之后,所以它会出现只有一个时字母已打印(不是预期的结果)。然而,一旦所有的字母被打印并且递归完成,“完成”警报就会正确显示,所以看起来好像我的延期变量在那之前不应该被解决。任何人都可以帮助我发现为什么“完成”警报在这里被称为早?任何帮助表示赞赏!

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

+0

非常感谢你到两个谁回答!将警报放入函数中修复它。 =)标记为正确,因为他先来了,但两个答案都是正确的,我删除了额外的'promise()'。再次感谢! – user2912928

回答

2

发生的事情,因为你实际上是在执行alert功能马上,而不是通过一个函数引用。

而是执行此操作:

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

或者

.then(function() { 
    alert('finished'); 
}); 
2

startButtonClick函数中,您不需要对showText的结果调用.promise(),因为您已经在showText的内部执行该操作。接下来,争论到then回调应该是一个功能,现在你会立即打电话报警功能,而不是将它作为一个功能,这就是为什么它会立即显示,所以只是把它包在一个函数:

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

这里是与代码的jsfiddle:http://jsfiddle.net/RnLXF/

1

这里与一大堆在一个可爱的小物体包裹起来小提琴:http://jsfiddle.net/YVZKw/3/

由于plalxctcherry has al已经准备好了,最大的问题是你的.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; 
}