【问题标题】:Can underscore debounce be called from a requires module?可以从需要模块调用下划线去抖动吗?
【发布时间】:2014-01-06 01:34:24
【问题描述】:

我无法在 requirejs 模块中使用下划线去抖动方法。作为替代方案,我可以通过 window.setTimeout 制作一个伪去抖动方法,但是我必须手动测试计时器。

有没有人创造出比这更好的选择?这是问题的一个jsfiddle: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();  

});

【问题讨论】:

标签: javascript requirejs underscore.js


【解决方案1】:

debouncedocumentation 表明去抖函数是从debounce返回的函数:

创建并返回传递函数的新去抖动版本

(添加了重点。)以下是文档中的示例:

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

注意使用的回调 (lazyLayout) 是来自debounce 的返回值。问题中的代码没有使用debounce的返回值,所以不起作用。

RequireJS 与此无关。

这是一个如何使用它的示例,基于问题中的flyStat.rptflyStat.rptd

// 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();
}

这是一个从你那里分叉出来的工作 fiddle。请注意,下划线必须是 shimmed 才能与 RequireJS 一起正常工作。 (此问题独立与您使用 debounce 的方式有关。)您的两个 CDN 都不起作用。此外,1.8 之前的 jQuery 版本不能识别 AMD 类型的加载器(如 RequireJS)。因此,除非有令人信服的理由使用旧版本,否则请使用最新版本。如果您必须使用无法识别 RequireJS 的旧版本,则必须对其进行填充。

(ETA:我从megawac对项目的github主分支中下划线版本支持AMD的问题的评论中看到。但是,这个版本似乎还没有发布。我不想与开发版本一起工作除非有一些真正令人信服的理由这样做。我关于下划线需要垫片的评论适用于迄今为止发布的下划线版本。大概,下一个版本不需要垫片。)

【讨论】:

  • 在此过程中,我停止调用 debounced 方法,感谢您的发现和您的见解。
【解决方案2】:

下划线的网址有误。要链接到 github javascript 文件,您应该使用 rawgithub.com.... 它将具有正确的标题。请注意,这仍然是一个糟糕的做法see this thread。使用:https://rawgithub.com/jashkenas/underscore/master/underscore.js

【讨论】:

  • 在我们的网站上,我们使用的是带垫片的下划线 1.4.4 + 要求,而 cdn 版本控制只是在 jsfiddle 中。谢谢建议,以后分享jsfiddles的时候会多加注意的。