Ask A Question

Notifications

You’re not receiving notifications from this thread.

Coffeescript Polling Issues

Chris Zempel asked in Javascript

I'd like to reload an iframe when the images needed to generate the preview it will display are cached by background workers. However, I can't figure out how to get setTimeout() to work correctly (or any other method of polling), and keep making thousands of immediate requests to my local machine which crashes the browser. While this is fun, I'd like it work.


class Preview
  constructor: (preview) ->
    @preview = preview
    @setBehavior()

  setBehavior: ->
    @loadWhenCached(@preview) unless @preview.data.footprintsCached?

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


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

You are calling loadWhenCached from inside loadWhenCached which is a recursive call. That's probably fine, but but you're not updating the footprintsCached value so it will always be false and it will always run again. Your success method needs to update the preview's footprintsCached attribute so that it can know not to do it again.

I'm curious why you need a loop at all? Issuing the first AJAX request should take care of it unless you have a reason that it's likely to fail. And if that's the case, you should consider pulling the loop out to a higher level rather than inside the method. That will help you manage it better so rather than making a recursive loop, you could do a setInterval that calls the method every couple seconds and then kills the interval once it has been successful.

Reply

One of the first SO results said "don't use setInterval," but that's exactly what I've been looking for.

The images will take anywhere between 15s and 120s to cache so this seems to be the most prudent way.

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

  loadWhenCachedPoll: ->
    @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. I'm thinking @interval or @loadWhenCached() fell out of scope, but I'm not sure why.

Reply
  loadWhenCached: ->

This might actually need to be a thick arrow so you can pass in @interval in the next callback too.

Reply

In coffeescript, when you call

@loadWhenCached()

it actually invokes the function. Because setInterval()'s context is the window, what happens is that it executed once successfully, then switch to the context of the window (where it no longer had access to @preview, or @interval) and started throwing that error.

What I needed to pass to the setInterval() was a reference to what function to invoke, not the actual invocation of the function.

@interval = setInterval(@loadWhenCached, 3000)

Additionally, I then needed to make sure that it was in the correct closure to grab stuff, meaning @loadWhenCached needs to use the fat => to ensure it takes place where it has access to @preview and @interval.

Reply

Ah yep, I overlooked the method call and thought you were just passing the reference. That'd do it!

Good debugging!

Reply

Wow, Chris is really becoming a rockstar! Good job!

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 82,464+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.