在Coffeescription中编写递归setTimeout循环

Writing a recursive setTimeout loop in Coffeescript

本文关键字:递归 setTimeout 循环 Coffeescription      更新时间:2023-09-26

我正在开发一个实时照片流应用程序。从本质上讲,用户将通过FTP将照片上传到我服务器上的文件夹中,并且页面应该在添加新照片时更新,而无需刷新。

我计划用AJAX和这个线程中建议的方法来做这件事:如何用PHP检查目录内容是否发生了变化?。本质上,我想在我的页面上有一个循环,每X秒对PHP页面进行一次AJAX调用,返回上传文件夹的目录列表的MD5哈希。如果自上次调用以来哈希发生了更改,则另一个AJAX调用将获得最近添加的文件,jQuery将在页面上显示该文件。

在vanilla Javascript/jQuery中,这可以使用一个递归的、命名的函数来完成,其中包含setTimeout

function refreshLoop(currentFolderState, refreshRate) {
    // Get the new folder state
    $.get("../ajax/getFolderState.php", function(data) {
        // If it's different than the current state
        if ( data !== currentFolderState ) {
            // Do something
        }
        // If it's the same as the current state
        else {
            // Do nothing
        }
        // After the refresh rate, try again
        setTimeout(function() {
            refreshLoop(data, refreshRate);
        }, refreshRate);
    });
}
// Document Ready
$(function() {
    var refreshRate = 5000;
    // After refresh rate has passed
    setTimeout(function() {
        // Get the starting folder state
        $.get("../ajax/getFolderState.php", function(data) {
            // Kick off the loop
            refreshLoop(data, refreshRate);
        });
    }, refreshRate);
});

我在这个项目中使用Coffeescapet是为了了解它的工作原理,因为很多开发人员似乎都喜欢它,但如果不使用命名函数,我就无法复制这个功能。有人能为我指明正确的方向吗?或者为我解释一种更好的方法来实现这种效果,这种方法可以在Coffeescapet中轻松完成吗?

更简洁的版本

do poll = ->
  #do work here
  setTimeout poll, 1000

它编译成

var poll;
(poll = function() {
  //do work here
  return setTimeout(poll, 1000);
})();

您可以在CoffeeScript:中执行类似操作

refresh_loop = (data, refresh_rate) ->
    #...etc
refresh_rate = 5000
setTimeout((->
    $.get("../ajax/getFolderState.php", (data) ->
        refresh_loop(data, refresh_rate)
), refresh_rate)

演示:http://jsfiddle.net/ambiguous/ZVTcg/

如果你的函数较小,那么你可以像这样内联所有函数:

refresh_rate = 5000
setTimeout(f = (->
    // real work goes here...
    setTimeout(f, refresh_rate)
), refresh_rate)

演示:http://jsfiddle.net/ambiguous/XThV6/

在您的情况下,嵌入所有内容可能会有点难看和令人困惑,因此使用单独的refresh_loop = (data, refresh_rate) -> ...构造可能是一个更好的主意。

我认为这里没有任何问题。您所要做的就是将refreshLoop分配给一个变量。以下是您的代码到CoffeeScript:的直接翻译

    refreshLoop = (currentFolderState, refreshRate) ->
        $.get '../ajax/getFolderState.php', (date) ->
            # ...
            setTimeout (-> refreshLoop(data, refreshRate)), refreshRate
    $ ->
        refreshRate = 5000
        setTimeout (->
            $.get '../ajax/getFolderState.php', (data) ->
                refreshLoop data, refreshRate
        ), refreshRate

但如果没有使用命名函数。

您可以使用这样的自调用匿名函数:

(function(){
   // do your stuff
   setTimeout(function(){
      arguments.callee();
   }, time);
})();

这里arguments.callee指的是匿名函数本身。

请注意,arguments.callee在ES5中已被弃用,但使用命名函数并没有错。