Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should nextTick and timers accept context or parameters? #953

Closed
benjamingr opened this issue Feb 25, 2015 · 10 comments
Closed

Should nextTick and timers accept context or parameters? #953

benjamingr opened this issue Feb 25, 2015 · 10 comments

Comments

@benjamingr
Copy link
Member

Currently, both timers and nextTick only take a callback argument (and some timers take a duration argument).

It is beneficial to pass additional arguments and/or the context to timers. The io.js code base is littered with code like:

  var self = this;
  process.nextTick(function() {
    self.emit('close');
  });

It's possible to either pass a context (this) to these functions or to pass arguments like the DOM version does making the above:

  process.nextTick(function() {
     this.emit('close');
   }, this);

Or:

  process.nextTick(function(element) {
     element.emit('close');
   }, this);

This can make cleaner code and save closure allocations - it also isn't slow like .bind.

Was this proposed before?

I realize the Timers API is locked (nextTick is not afaict) but I'm wondering how people feel about this.

@vkurchatkin
Copy link
Contributor

@benjamingr
Copy link
Member Author

Thanks! Looks like it's still open in node from 2013.

@vkurchatkin
Copy link
Contributor

Thanks! Looks like it's still open in node from 2013.

That doesn't mean anything. I saw open reasonable feature requests dated 2010 :)

My opinion: we can make internal nextTick with this feature and try it out. Eventually it can be exposed

@bnoordhuis
Copy link
Member

It would probably make the nextTick() code significantly more complex, though - and it's already pretty complex to start with. It's also extremely performance sensitive, it would be very easy to introduce performance regressions.

@vkurchatkin
Copy link
Contributor

Looks pretty straightforward:

diff --git a/src/node.js b/src/node.js
index f0bee17..e8a07b5 100644
--- a/src/node.js
+++ b/src/node.js
@@ -307,7 +307,8 @@

       nextTickQueue.push({
         callback: runMicrotasksCallback,
-        domain: null
+        domain: null,
+        context: null
       });

       tickInfo[kLength]++;
@@ -334,7 +335,7 @@
         callback = tock.callback;
         threw = true;
         try {
-          callback();
+          callback.call(tock.context);
           threw = false;
         } finally {
           if (threw)
@@ -360,7 +361,7 @@
           domain.enter();
         threw = true;
         try {
-          callback();
+          callback.call(tock.context);
           threw = false;
         } finally {
           if (threw)
@@ -375,14 +376,15 @@
       tickDone();
     }

-    function nextTick(callback) {
+    function nextTick(callback, context) {
       // on the way out, don't bother. it won't get fired anyway.
       if (process._exiting)
         return;

       var obj = {
         callback: callback,
-        domain: process.domain || null
+        domain: process.domain || null,
+        context: context
       };

       nextTickQueue.push(obj);

@benjamingr
Copy link
Member Author

Yes, and doing the changes @vkurchatkin proposed will actually allow cleaning a bunch of self = this code (in addition to being faster - although this issue isn't a perf request)

@rvagg
Copy link
Member

rvagg commented Feb 25, 2015

I'm pretty sure I even put in a PR for this once because the symmetry with setTimeout() was too tempting

However, nextTick() isn't even encouraged these days, it should be considered more of an internal feature and users should be generally opting for setImmediate() which has all of this (doesn't it?). nextTick() needs to be fast and keeping it simple is going to help with that.

So -1 from me.

@benjamingr
Copy link
Member Author

@rvagg I'm not convinced nextTick should support a context or argument parameter but for what it's worth the issue was raised because I saw var self = this inside the core code base in several places and thought that it could be a nice way to clean up the code base.

@rvagg
Copy link
Member

rvagg commented Feb 25, 2015

@benjamingr performance has always won over "clean code" in core so in general I think you might have a hard time cleaning anything up that has performance tradeoffs.

@benjamingr
Copy link
Member Author

@rvagg it's actually much faster to pass context than to use a closure - this is actually an optimisation that several PRs (like the recent fs performance PR) utilize.

That said I have nothing solid at this stage to indicate that performance will improve because of this here and since that code is sensitive unless someone wants to do all the work involved in profiling it I'm afraid it indeed might be better to 'leave it be' at this stage.

It seems that timers already support this. So I'm closing this right now - something to consider in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants