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

[feature] Promise returning process.nextTick #19617

Closed
jamiebuilds opened this issue Mar 26, 2018 · 25 comments
Closed

[feature] Promise returning process.nextTick #19617

jamiebuilds opened this issue Mar 26, 2018 · 25 comments
Labels
feature request Issues that request new features to be added to Node.js. process Issues and PRs related to the process subsystem. promises Issues and PRs related to ECMAScript promises.

Comments

@jamiebuilds
Copy link
Contributor

Just a quick idea I had after talking to @sindresorhus.

When process.nextTick() is called without a function, return a Promise:

async function fn() {
  await process.nextTick();
}

in effect:

function nextTick(fn) {
  if (typeof fn === 'function') {
    process.nextTick(fn);
  } else {
    return new Promise(res => process.nextTick(res));
  }
}

As more of Node (possibly) moves to Promises/async-await for APIs (#15413) this makes sense I think

@addaleax addaleax added feature request Issues that request new features to be added to Node.js. process Issues and PRs related to the process subsystem. promises Issues and PRs related to ECMAScript promises. labels Mar 26, 2018
@addaleax
Copy link
Member

I think it would be helpful to know about use cases that are not already covered by Promise.resolve()? I understand that these two are not equivalent, but it seems for most well-written code that they should work just the same.

@sindresorhus
Copy link

await Promise.resolve(); doesn't show clear intent.

@addaleax
Copy link
Member

@sindresorhus If that is the argument, we probably shouldn’t overload process.nextTick() for this either, but rather give it a new name. :)

(But still, I am not sure that I ever wanted to use some kind of artificial deferral in an async function – that means it’s depending on the relative timing of some other thing, which is almost always a code smell imo…)

@sindresorhus
Copy link

(But still, I am not sure that I ever wanted to use some kind of artificial deferral in an async function – that means it’s depending on the relative timing of some other thing, which is almost always a code smell imo…)

process.nextTick() and setImmediate() are widely used, so there are lots of valid reasons for using them. For example, async functions are not actually async until you await something async, so if you want to ensure something will be async, you could use it.

@TimothyGu
Copy link
Member

IIRC one could also do await 'next tick';. I’d shy away from adding/using something Node.js-specific when the concept of waiting for the next tick apply to non-Node.js platforms as well.

@sindresorhus
Copy link

@TimothyGu I've been using async/await since it was introduced in Babel and I've never thought of doing that. It's an ok workaround, but not a nice general solution.

@rg1220
Copy link

rg1220 commented Mar 29, 2018

Sounds like this would be better to add to the Promise implementation:

await Promise.nextTick();

Although I'd think it would be better left to a Promise library like Bluebird.

@vkurchatkin
Copy link
Contributor

If you just want to show intent, you can do this:

async function fn() {
  await process.nextTick;
}

@sindresorhus
Copy link

I just realized, what I actually want is an await-friendly setImmediate().

See: https://stackoverflow.com/a/15349865/64949

@sindresorhus
Copy link

sindresorhus commented Mar 29, 2018

Sounds like this would be better to add to the Promise implementation:

There's a much higher bar to adding things to Promise than just making egonomics additions to existing Node.js APIs. Browsers have been resistant to adding setImmediate, so I doubt they would be open to adding an await-friendly version of it.

@statianzo
Copy link

Isn't this the purpose of util.promisify?

const util = require('util');
const nextTick = util.promisify(process.nextTick);
// ...
await nextTick();

@sindresorhus
Copy link

sindresorhus commented Mar 29, 2018

I consider await 'next tick'; and await process.nextTick; both just hacks that takes advantage of a quirk in await (that you can await anything). It does not result in readable code and everyone will end up doing it differently (await 'smoosh'; 😝). We need an official solution for this, not local workarounds.

@apapirovski
Copy link
Member

apapirovski commented Mar 29, 2018

@sindresorhus Would the promisified version of setImmediate not do the trick? I realize it's not completely plug and play but I can't imagine this making it into core unless there's a major effort to include promisified versions of all the APIs. There aren't even any semantic or performance benefits to including it.

We need an official solution for this, not local workarounds.

I mean, you're basically asking for await process.nextTick but with an explicit variable intended for this purpose. It could literally be a global variable set to null or true or something. I'm really not a fan...

@sindresorhus
Copy link

Isn't this the purpose of util.promisify?

util.promisify is just a stop-gap.

@timoxley
Copy link
Contributor

Are there any differences in timing, queue priority, etc between process.nextTick and await?

@sindresorhus
Copy link

but I can't imagine this making it into core unless there's a major effort to include promisified versions of all the APIs.

Well, there is: 329fc78

@sindresorhus
Copy link

Are there any differences in timing, queue priority, etc between process.nextTick and await?

https://jsblog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa

@apapirovski
Copy link
Member

Are there any differences in timing, queue priority, etc between process.nextTick and await?

@timoxley All queued nextTicks would run first, then all await would trigger once that queue is empty. But that's the same whether we create a custom version of process.nextTick or just await 'next-tick';.

Strictly speaking, if we returned a promise and only resolved it in the nextTick queue then the ordering would actually be more messed up than with awaiting something that's not a promise (or awaiting Promise.resolve(1)).


@sindresorhus The fs/promises stuff has API and performance implications. Promisified setImmediate and nextTick don't. They would be equivalent.

@sindresorhus
Copy link

The fs/promises stuff has API and performance implications. Promisified setImmediate and nextTick don't. They would be equivalent.

I'm not talking about performance, I mean exposing promise APIs over util.promisify.

@apapirovski
Copy link
Member

apapirovski commented Mar 29, 2018

I'm not talking about performance, I mean exposing promise APIs over util.promisify.

I'm not just talking about performance. There's more to the promisifed fs module that can't easily be done in userland or just by using util.promisify.

I also don't believe that making the current functions be polymorphic is a great idea, which means that shipping promisifed setImmediate and nextTick is asking core to add something akin to:

global.setImmediateAsync = util.promisify(setImmediate);

process.nextTickAsync = (arg) => Promise.resolve(arg);

I mean, that's literally the PR there... with some bike-shedding for the naming.

@YurySolovyov
Copy link

What about new function with a better name and API then?
One that will fix nextTick vs. setImmediate naming confusion once and for all.
Cause nextTick is actually more like current tick with respect to IO

@benjamingr
Copy link
Member

I see absolutely zero reason to promisify or await nextTick. I see why it would be nice to have in theory but I simply do not see any use case.

A bigger problem is that it would be lying, when I execute a nextTick action it'll execute in order with other nextTicks but these will execute later when promises resolve.

@benjamingr
Copy link
Member

Also, reading your comment @sindresorhus that is a lot more likely and makes sense (async setImmediate). We already support this through util.promisify and we can escape the spec.

I've opened an issue about this (for setTimeout): #19426

@benjamingr
Copy link
Member

It seems like discussion has exhausted itself.

If anyone feels strongly, feel free to reopen.

@ryanmtaylor
Copy link

Worth mentioning that it is almost always better to use setImmediate instead of nextTick – also is await new Promise(resolve => setImmediate(resolve)); realllly that bad?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. process Issues and PRs related to the process subsystem. promises Issues and PRs related to ECMAScript promises.
Projects
None yet
Development

No branches or pull requests