Search code examples
javascriptjquerycoffeescriptpolling

Ajax polling in Coffeescript - whats falling out of scope and why?


I'd like to reload an iframe when the images needed to generate the preview it will display are cached by background workers (which can take a little while.)

class Preview
  constructor: (preview) ->
    @preview = preview
    @loadWhenCachedPoll() unless @preview.data?.footprintsCached?

  loadWhenCachedPoll: ->
    @interval = null
    @interval = setInterval(@loadWhenCached(), 3000)

  loadWhenCached: ->
    console.log "polling"
    $.ajax(
      url: "/user_image_caches/cached",
      method: "GET"
      dataType: "JSON"
      success: (data) =>
        if data["cached"] == "true"
          clearInterval(@interval)
          @preview.data.footprintsCached.val("true")
          @preview.attr('src', '/certificate.pdf')
    )

jQuery ->
  new Preview $("[data-behavior='preview']")

It runs successfully the first time, then every time after that I get Uncaught SyntaxError: Unexpected identifier

signaling that something fell out of scope.


Solution

  • You have two errors:

    1. You're calling setInterval with loadWhenCached's return value instead of the loadWhenCached function itself.
    2. loadWhenCached is not bound to anything so this won't be what you expect it to be when setInterval calls it.

    The first one is easy to fix, pass the function reference rather than calling the function:

    setInterval(@loadWhenCached, 3000) # No function-calling parentheses
    

    Your version is calling loadWhenCached while the argument list for setInterval is being built rather than being called by setInterval.

    The second can be fixed in various ways. You can make loadWhenCached a bound method using a fat-arrow:

    loadWhenCached: =>
      #...
    

    or you could bind it using Function.prototype.bind when calling setInterval:

    setInterval(@loadWhenCached.bind(@), 3000)