1

The following is not a problem per se, because it can be avoided by not using the same name for two asset pipeline files. I am simply curious about an explanation, so thanks for any insight.

This is Rails 3.2.6, sprockets 2.1.4 (also tried with latest, 2.4.4). A minimal example: http://github.com/richardkmichael/js-test

I have a FooController, and am writing javascript not coffeescript, so I've created a new file foo.js, but left an empty foo.js.coffee.

I have a setInterval() function (testing readyState === 'complete') which is stopped with clearInterval(). However, the interval function loops, as if the clearInterval() call is not working.

When I remove the empty foo.js.coffee file, the looping stops and the JS works as expected. Replacing the empty foo.js.coffee starts the looping behaviour on the client again.

The server-side processing appears to be changing something client-side, causing a reset/new interval timer?

There does not appear to be a client-side JS difference between these two cases. However, in Chrome's web inspector:

  • 'Resources' lists foo.js once and in both cases contains exactly the JS as it appears foo.js server-side. application.js contains a single semi-colon. (Aside, this looping behaviour remains even if I remove jQuery.)

  • 'Sources' (localhost / assets) lists foo.js?body=1 twice.

app/controllers/foo_controller.rb:

class FooController < ApplicationController
  def index
    render :inline => '<p>Hello, World!</p>', :layout => true
  end
end

app/assets/javascripts/foo.js:

var readyStateCheckInterval = setInterval(function () {
  if (document.readyState === 'complete') {
    console.log('Document ready.');
    clearInterval(readyStateCheckInterval);
  }
}, 2000);

app/assets/javascripts/foo.js.coffee:

<empty -- just `touch .../foo.js.coffee`>

A (perhaps) similar question: sprockets duplicate file naming

UPDATE

Based on the responses, I noticed there were two <script> tags (rather obvious in hindsight). Testing Frederick's explanation, I changed the javascript to avoid losing the first timer reference, and it "works" (exactly two writes to console.log) as expected.

/*jslint indent: 2 */

(function () {

  'use strict';

  var intervalTimers = {},
    date = new Date(),
    time = date.getTime();

  function setupIntervalTimer(name) {
    intervalTimers[name] = setInterval(function () {
      if (document.readyState === 'complete') {
        console.log('Document ready.');
        clearInterval(intervalTimers[name]);
      }
    }, 2000);
  }

  setupIntervalTimer(time);

}());
4
  • For the record, you can put vanilla javascript into a coffeescript file and be just fine. You don't need to create a separate file. The golden rule of CoffeeScript is: "It's just JavaScript" Commented Jul 9, 2012 at 15:38
  • Yes, thanks, I'm aware of that. It's partly the reason I thought sprockets might just concat everything from *.js, *.coffee.js, and other engines and serve it all out. Commented Jul 10, 2012 at 8:14
  • 1
    What are the <script> tags in the case where both foo.js and foo.js.coffee exist? Commented Jul 10, 2012 at 15:04
  • Indeed, when foo.js.coffee exists there are two <script> tags (both include "foo.js?body=1"); without it, only one. I missed this obvious fact when flipping back and forth between "tests" - arg! Thanks for your reply, Trevor! Commented Jul 11, 2012 at 14:42

1 Answer 1

3

Your Javascript is being included twice. The network inspector is likely only showing it once because the browser is smart enough not to fetch the same file again

When your first copy of the Javascript runs it creates your timer and stashes its value in readyStateCheckInterval so that it can cancel it later. The second copy creates a second timer and overwrites the value of readyStateCheckInterval with the new value. Your callbacks then end up trying to cancel the second timer twice but never cancel the first one (since you've now lost your reference to it)

Sign up to request clarification or add additional context in comments.

1 Comment

As you and Trevor suggested, it is included twice (when I checked the differences more carefully, I noticed the second <script> tag). I'll also dig into the Chrome dev tools deeper, I should be able to debug the reassignment to readyStateCheckInterval. Thank you Frederick!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.