2012-03-08 112 views
4

我正在处理实时照片流应用程序。实质上,用户将通过FTP将照片上传到服务器上的文件夹,并且每次添加新照片时页面都应该更新而不刷新。在Coffeescript中编写递归setTimeout循环

我打算使用AJAX和本主题中建议的方法执行此操作:How to check if directory contents has changed with 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); 

}); 

我使用的CoffeeScript在这个项目上,试图了解它是如何工作的,因为很多开发商似乎喜欢它,但我想不出如何在不使用命名函数的情况下复制此功能。某人能否指引我朝着正确的方向发展,还是解释一种更好的方式来实现这种可以在Coffeescript中轻松完成的效果?

回答

4

你可以做这样的事情在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/

Inlini所有它可能会有点丑陋和混淆你的情况,尽管如此使用一个单独的refresh_loop = (data, refresh_rate) -> ...构造可能是一个更好的主意。

+0

我可以发誓我在某个时候尝试过这样做,但它不起作用,但我想我还有其他的犯规。谢谢! – 2012-03-08 20:51:44

+0

@Ryan:你可能省略了额外的圆括号,CoffeeScript的隐含块结构有时会造成一些混乱。 – 2012-03-08 21:13:53

+1

完美。内联功能已准备就绪。未来的读者,如果你在'f ='函数内使用任何'@'引用,你可能想更新它到'(=>',这样它就能正确捕获原始范围。 – 2016-06-16 18:51:20

2

但我不知道如何复制这个功能没有 使用命名函数。

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

(function(){ 
    // do your stuff 

    setTimeout(function(){ 
     arguments.callee(); 
    }, time); 
})(); 

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

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

+0

我发现了一个关于参数的建议。被调用者也在其他地方,但JSHint给了我一个警告,我发现很多建议,说它一般不好用。潜在的问题是什么让它听起来很可怕? – 2012-03-08 20:15:32

+1

'arguments.callee'结构已弃用。它也会导致性能问题。 – Pointy 2012-03-08 20:16:20

+0

这些是可怕的话听。 – 2012-03-08 20:19:08

4

我在这里没有看到任何问题。你所要做的就是将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 
+0

我个人喜欢用别名''setTimeout'方法被称为'delay',参数反转如下:'delay =(ms,cb) - > setTimeout(cb,ms)'这样我可以稍后调用它:'delay refreshRate, - >“做某事......“'看起来好多了,没有多余的括号,我想我甚至从你的回复中看到了这个。 – Sandro 2012-03-08 20:57:51

+0

@Sandro是的,这绝对会让事情变得更好,我只是想直接回答问题 – 2012-03-08 21:35:46

+0

这正是我最初尝试做的事情,我必须在某个地方出现语法错误,这会让我感到困惑。而且,这个延迟别名是一个好主意,我想我可能会在将来使用。 – 2012-03-08 21:56:11

6

一个更简洁的版本

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

其编译成

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

FWIW此方法似乎只与' - >'和'=>'兼容,需要更复杂的上下文纠缠设置 – 2016-06-16 19:19:05