Как определить функцию обратного вызова с Coffeescript и Rails 3.1? - PullRequest
3 голосов
/ 26 июля 2011

На мой взгляд, я хочу:

: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 будет видимым, но данные всегда возвращаются как [].

Ответы [ 2 ]

5 голосов
/ 26 июля 2011

То, что происходит, заключается в том, что вы обрабатываете асинхронный код, как если бы он был синхронным.Некоторые выходные данные отладки могут помочь вам визуализировать это:

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

Я немного подробнее расскажу о JSмодель события в моей книге CoffeeScript .Кроме того, Джон Ресиг Как работают таймеры JavaScript необходимо прочитать.Асинхронность требует некоторого привыкания, но преимущества многопоточности впечатляют.

2 голосов
/ 26 июля 2011

изменить Gmap = ... на window.Gmap = ....

решит проблему.Причина в том, что coffeescript упаковывает все в анонимную функцию.Если вы хотите более полнофункциональную модульную систему, посмотрите здесь

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

...