18

This is the source code for Underscore.js' delay function:

_.delay = function (func, wait) {
    var args = slice.call(arguments, 2);
    return setTimeout(function () { return func.apply(null, args); }, wait);
};

How is this any different from setTimeout? Why does Underscore.js need delay?

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299

4 Answers4

24

It's a cross browser way of being able to pass extra arguments which will appear as the arguments to the callback, like setTimeout(). This doesn't work in IE.

It can make your code prettier...

setTimeout(_.bind(function() { }, null, "arg1"), 1e3);

...vs...

_.delay(function() { }, 1e3, "arg1");

I agree that it's one of the less useful Underscore methods, which are outlined in Naomi's answer.

Community
  • 1
  • 1
alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    Internet Explorer doesn't support [callback arguments](https://developer.mozilla.org/en-US/docs/Web/API/window.setTimeout#Callback_arguments). What a b****! – Aadit M Shah Jun 03 '13 at 05:02
  • @Alex—it doesn't support passing a string literal as the first parameter, so not *that* cross browser. Perhaps that's mentioned in the documentation… – RobG Jun 03 '13 at 05:22
  • @RobG Well, I don't think that's a feature we want to keep :) – alex Jun 03 '13 at 05:27
  • @RobG and __why__ would you want to call a function based on a string? Never mind, if your javascript doesn't work, just wrap it in an additional `$()` call. – Mulan Jun 03 '13 at 05:43
  • @alex, I don't think this has **anything** to do with cross browser compatibility. It's just a convenience function for people that doesn't really have a purpose in the first place if you simply understand how to use javascript's native `.bind`, `.call`, or `.apply` functions. – Mulan Jun 03 '13 at 05:48
  • @naomik You could say the same about a lot of Underscore functions. – alex Jun 03 '13 at 05:57
  • @alex, then maybe don't say something about "cross browser" when that's completely not true or relevant. – Mulan Jun 03 '13 at 06:01
  • 1
    @naomik How is it irrelevant? Underscore provides (among other things) missing functionality that isn't in all browsers. Here is another example that allows passing additional arguments to be passed to the callback. That isn't supported in IE. It's a possible reason why this function exists. – alex Jun 03 '13 at 06:07
  • @alex, `_.delay` does **not** provide extra functionality; in fact, it provides less if you consider the fact that there's no way to set the context for the function you want to delay. (See my answer for more details about context). True, `setTimeout` doesn't behave identically in every browser, but you can pass the additional arguments using `.bind` like you should be doing in the first place. – Mulan Jun 03 '13 at 06:10
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/31088/discussion-between-alex-and-naomik) – alex Jun 03 '13 at 06:14
  • 1
    @naomik—mine is not to reason why, just to comment. ;-) I might pass a string to setTimeout if it was something trivial like `alert('boo')`. But then I can also do `setTimeout(Function('…'),…)`, so what is gained by not supporting strings? – RobG Jun 03 '13 at 06:20
17

Why does Underscore.js have a delay function?

Because dumb. This particular underscore.js method seems pretty stupid.

Cons

  1. additional function in lib means larger code base
  2. larger code base means more to maintain and more possible bugs
  3. code that uses this function now has a dependency on that lib
  4. lesser/nil improvement over native API means low cost:gain ratio
  5. new apis to learn

Pros

this section intentionally left blank


I would just learn to use javascript and do something like

var hello = function() {
  console.log("hello");
};

var delay = 1000;

window.setTimeout(hello, delay);

Simple, right? Underscore.js is sometimes pretty useless. Honestly, window.setTimeout is perfectly useful just the way it is.


Here's another example to show how to pass an arg to the function

var Cat = function(name) {
  function meow(message) {
    console.log(name, "says meow!", message);
  }
  this.meow = meow;
};

var duchess = new Cat("Duchess");

window.setTimeout(duchess.meow.bind(duchess, "please feed me!"), 2000);

// 2 seconds later
// => Duchess says meow! please feed me!

If you can't depend on .bind you can use a closure too

window.setTimeout(function() {
  duchess.meow("please feed me!");
}, 1000);

Wow, that was difficult, though. I'm going back to underscore and lodash and jquery. This JavaScript stuff is tough !

Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 5
    I understand your approach, however once you start down the road of a general library, you soon find yourself wrapping everything so as not to expose the underlying API (e.g. jQuery wraps everything under the sun). Otherwise, users start get confused over what is the library and what is native JS or DOM or whatever you're abstracting. Not supporting one approach over the other, just saying. – RobG Jun 03 '13 at 06:24
  • 3
    Bunch of noobs still down-voting this. Keep 'em coming, rookies :) – Mulan Aug 21 '14 at 05:22
  • 1
    I don't understand all the hate. You don't deserve to be downvoted. – Aadit M Shah Sep 23 '14 at 02:26
  • 3
    @RobG I disagree. I don't think a lib's goal should be to completely replace all the native functionality of a language. Even if it's a utility library, it should maintain a clear focus on things it's actually improving upon. In this case, `_.delay` is not enough of an improvement (or an improvement at all) to warrant the abstraction and additional API to memorize. – Mulan Sep 23 '14 at 07:34
10

aes·thet·ics

The author of that library, who chose to spend his/her spare time to open source it, talk about it, use it as a way to introduce people to javascript and perhaps get someone to have a light-bulb moment around closure scope thought the library's attractiveness was enhanced by having this.

Arguing the relevancy of this function in isolation is like arguing the relevancy of a painting or other piece of craftsmanship. Some may like it, others may not.

You are free to like it or not. I, personally, prefer just-get-to-the-point libs.

_.delay, _.defer, _.throttle, _.after have a flow IMHO that reads better than window.

On-top of this, generally I also like writing node server side (nodejs) and not have to shift/in/out of mode... try using window.timeout in node and see what happens.

4

Not much, although it fits thematically with defer, debounce, and so on. This means you can use the underscore wrapping notation:

_(yourfunction).delay(1000);

Also it doesn't seem like it will let you get away with a string argument, which would call eval.

Plynx
  • 11,341
  • 3
  • 32
  • 33
  • 3
    I don't think anybody in their right mind would pass a string to `setTimeout`. – Aadit M Shah Jun 03 '13 at 05:13
  • @plynx—not necessarily *eval*, it might instead use the Function constructor. ;-) @Aadit—not hard to support strings too, just test the first argument and if it's a string, use the Function constructor, then call set timeout with that. – RobG Jun 03 '13 at 05:27
  • 1
    @AaditMShah robg You both seem to be misunderstanding me—I'm referring to the benefit of not accepting string arguments. I've seen it happen lots of times, and even sometimes by accident. You can find many examples in code here on StackOverflow. Programmer's hands are strange things and sometimes they put quotes around things when you're not looking. – Plynx Jun 04 '13 at 01:22
  • 1
    @Plynx - I understand you. I also understand that `delay` is safer because you can't pass it a string argument. I still think that nobody in their right mind would pass `setTimeout` a string. You make it sound almost comical by saying, "programmers' hands are strange things and sometimes they put quotes around things when you're not looking." Next time you see the work of those hands please let them know that I think that they should consult the brain before playing dangerous games. Also you forgot to put an at sign before mentioning @RobG. – Aadit M Shah Jun 04 '13 at 03:28
  • @AaditMShah Thanks. I didn't forget, but the comment system informed me that I can only put one mention, which seems to me like a strange restriction. As for no one in their right mind doing such a thing, it's an academic argument. I could say I agreed with you but it wouldn't change the fact that programmers are out there every day doing it, for whatever reason, even programmers who know to avoid eval on user data, whether due to inexperience in JS syntax or supporting legacy code, whatever. For this reason it's not allowed in Javascript's strict mode. – Plynx Jun 04 '13 at 20:37