如何使用 Coffeescript 和 Rails 3.1 定义回调函数?

发布于 2024-11-26 04:37:58 字数 536 浏览 1 评论 0原文

在我看来,我想要:

:coffeescript
  Gmap('#canvas').getAddressBounds request.term

在maps.js.coffee 中定义为但这

Gmap = (mapId) ->
  getAddressBounds: (address) ->
    data = []
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        return unless results
        data = $.map results, (item) ->
          bounds: item.geometry.bounds
    data

不起作用。首先,有一个范围问题。 Gmap 函数对于视图中的脚本不可见。如果我将代码直接添加到视图中,Gmap 是可见的,但数据始终返回为 []。

In my view I want:

:coffeescript
  Gmap('#canvas').getAddressBounds request.term

which is defined in maps.js.coffee as

Gmap = (mapId) ->
  getAddressBounds: (address) ->
    data = []
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        return unless results
        data = $.map results, (item) ->
          bounds: item.geometry.bounds
    data

This doesn't work though. First, there's a scope issue. The Gmap function is not visible to the script in the view. If I add the code directly to the view, Gmap is visible, but data always returns as [].

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤蝉 2024-12-03 04:37:58

发生的情况是,您将异步代码视为同步代码。一些调试输出可能会帮助您直观地看到这一点:

Gmap = (mapId) ->
  getAddressBounds: (address) ->
    data = []
    console.log '1: Calling gmap3'
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        console.log '3: Callback called'
        return unless results
        data = $.map results, (item) ->
          bounds: item.geometry.bounds
    console.log '2: Returning data'
    data

当您传递回调时,它可以随时被调用。如果在 gmap3 函数期间调用它,则 data 在返回之前确实会被设置。但是 gmap3 使用回调来返回其结果而不仅仅是返回的原因是该函数是异步的,特别是当服务器响应您的查询时它会调用回调。 JavaScript 处理事件的方式意味着您的回调保证在所有代码执行完毕之前不会被调用。

在 JavaScript(或 CoffeeScript)中,无法将异步函数包装在同步函数中;即使运行无限循环直到调用回调也是行不通的,因为在所有代码执行完毕之前,JS 运行时不会处理服务器响应(甚至用户输入事件)等事件。因此,您所能做的就是更改您的函数,以使用回调:

Gmap = (mapId) ->
  getAddressBounds: (address, cb) ->
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        return unless results
        cb $.map results, (item) ->
          bounds: item.geometry.bounds

然后像这样调用它:

 Gmap('#canvas').getAddressBounds request.term, (data) -> console.log data

我在 我的 CoffeeScript 书。此外,John Resig 的 JavaScript 计时器工作原理 也是必读之作。异步性需要一些时间来适应,但相对于多线程的好处是惊人的。

What's going on is that you're treating asynchronous code as if it's synchronous. Some debug output might help you visualize this:

Gmap = (mapId) ->
  getAddressBounds: (address) ->
    data = []
    console.log '1: Calling gmap3'
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        console.log '3: Callback called'
        return unless results
        data = $.map results, (item) ->
          bounds: item.geometry.bounds
    console.log '2: Returning data'
    data

When you pass a callback, it could get called at any time. If it were called during the gmap3 function, then data would indeed be set before being returned. But the reason gmap3 uses a callback to return its result, rather than just returning, is that the function is asynchronous—in particular, it calls the callback when the server responds to your query. The way that JavaScript does events, that means your callback is guaranteed not to be called until after all code has finished executing.

There's no way to wrap an asynchronous function in a synchronous one in JavaScript (or CoffeeScript); even running an infinite loop until your callback is called wouldn't work, because, again, the JS runtime doesn't handle events like server responses (or even user input events) until all code has finished executing. So all you can do is change your function, too, to use a callback:

Gmap = (mapId) ->
  getAddressBounds: (address, cb) ->
    $(mapId).gmap3
      action: 'getAddress'
      address: address
      callback: (results) ->
        return unless results
        cb $.map results, (item) ->
          bounds: item.geometry.bounds

Then call it like so:

 Gmap('#canvas').getAddressBounds request.term, (data) -> console.log data

I talk a little bit more about the JS event model in my CoffeeScript book. Also, John Resig's How JavaScript Timers Work is a must-read. Asynchronicity takes some getting used to, but the benefits over multithreading are spectacular.

む无字情书 2024-12-03 04:37:58

改变
地图=...

window.Gmap = ....

将解决问题。原因是 CoffeeScript 将所有内容都包装在匿名函数中。如果您想要一个功能更齐全的模块系统,请查看这里

https: //github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript

change
Gmap = ...
to
window.Gmap = ....

will solve the problem. The reason is coffeescript wraps everything in an anonymous function. If you want a more feature full module system have a look here

https://github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文