0

I could not get the underscore debounce method to work from within a requirejs module. As an alternative, I can make a pseudo-debounce method via the window.setTimeout, but then I have to test the timer manually.

Has anyone created a better alternative than this? Here is a jsfiddle of the problem: http://jsfiddle.net/ledlogic/gkY5C/

require.config({
paths: {
    'jquery': 'http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.min',
    'underscore': 'https://raw.github.com/documentcloud/underscore/master/underscore'
}
});

require(['jquery', 'underscore'], function ($, _) {
var flyStat = {
    pct: -1,
    delay: 0,
    timeout: null,

    rnd: function (i) {
        flyStat.pct = Math.random() * 100.0;
        flyStat.trns(i);
    },
    // report transient state.  CALLED
    trns: function (i) {
        console.log("TRNS[" + i + "]: " + flyStat.pct);
    },
    // report final state, called immediately at end. CALLED
    rpt: function () {
        console.log("RPT: " + flyStat.pct);
    },
    // report final state, intended to be called from debounce. NOT CALLED
    rptd: function () {
        console.log("RPTD: " + flyStat.pct);
    },
    // report final state, setup timeout calls.  CALLED
    rpto: function(delay) {
        if (flyStat.timeout) {
            window.clearTimeout(flyStat.timeout);
        }
        flyStat.last = (new Date()).getTime();
        flyStat.delay = delay;
        flyStat.timeout = window.setTimeout(flyStat.rpto2, delay);
    },
    // report final state, called from timeout call.  CALLED
    rpto2: function() {
        if (flyStat.last > flyStat.delay) {
            console.log("RPTO2: " + flyStat.pct);
        }
    }
};

// Can debounce call back into a requires define block?
// NO.
function dbc() {
    console.log("DBC: 1");
}
_.debounce(dbc, 10);

// Run a semi-lengthy running process (because of the console log activity, it lags a bit).
for (var i = 0; i < 1000; i++) {
    flyStat.rnd(i);

    // We want a debounced report, after 1 sec past the last one
    // Do we get it?
    // NO.
    _.debounce(flyStat.rptd, 1000);

    // Can we resort to classic timeout?
    // YES.
    flyStat.rpto(1000);

    // Is there a better way?
    // UNKNOWN.
}

// Immediate call at end (assumes we have sequential process with fixed known length and endpoint).
// Does this work?
// YES.
flyStat.rpt();  

});
ledlogic
  • 774
  • 1
  • 9
  • 19
  • 1
    "Can debounce call back into a requires define block?" What does that mean? – ZenMaster Dec 18 '13 at 02:22
  • Underscore doesnt support amd module loaders - edit the one on github does but you have the wrong link use: https://rawgithub.com/jashkenas/underscore/master/underscore.js – megawac Dec 18 '13 at 02:24

2 Answers2

1

You have the wrong url to underscore. For linking to github javascript files you should use rawgithub.com.... which will have the right headers. Note that this is still a poor practice see this thread. Use: https://rawgithub.com/jashkenas/underscore/master/underscore.js

Community
  • 1
  • 1
megawac
  • 10,953
  • 5
  • 40
  • 61
  • On our site we are using the shimmed underscore 1.4.4 + require, and the cdn versioning is just in jsfiddle. Thanks for the suggestion, I'll pay more attention in the future when sharing jsfiddles. – ledlogic Dec 18 '13 at 21:32
1

The documentation for debounce shows that the debounced function is the one which is returned from debounce:

Creates and returns a new debounced version of the passed function

(Emphasis added.) Here's the example from the documentation:

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

Note how the callback used (lazyLayout) is the return value from debounce. The code in the question does not use the return values from debounce, so it does not work.

RequireJS has no bearing at all on this.

Here's an example of how to use it, based on flyStat.rpt and flyStat.rptd from the question:

// Define flyStat but don't define rptd right away
var flyStat = {
[...]
};

// Create the debounced version of rpt.
flyStat.rptd = _.debounce(flyState.rpt, 1000);

for (var i = 0; i < 1000; i++) {
     flyStat.rnd(i);
     // Call the debounced version.
     flyStat.rptd();
}

Here is a working fiddle forked from yours. Note that underscore must be shimmed to work properly with RequireJS. (This problem is independent from the problem with how you used debounce.) Neither of your CDNs worked. Also, jQuery versions prior to 1.8 did not recognize AMD-type loaders (like RequireJS). So unless there's a compelling reason to use an old version, use the latest. If you must use an old version that does not recognize RequireJS, you must shim it.

(ETA: I see from megawac's comment on the question that the version of underscore in github's master branch for the project has AMD support. However, this version does not seem to be released yet. I prefer not to work with development versions unless there's some really compelling reason to do so. My comment about underscore needing a shim holds for versions of underscore released to this date. Presumably, the next version won't need a shim.)

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Somewhere along the way I stopped calling the debounced method, thanks for catching that, and your insights. – ledlogic Dec 18 '13 at 21:30