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
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.
await Promise.resolve();
doesn't show clear intent.
@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…)
(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.
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.
@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.
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
.
If you just want to show intent, you can do this:
async function fn() {
await process.nextTick;
}
I just realized, what I actually want is an await-friendly setImmediate()
.
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.
Isn't this the purpose of util.promisify
?
const util = require('util');
const nextTick = util.promisify(process.nextTick);
// ...
await nextTick();
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.
@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...
Isn't this the purpose of util.promisify?
util.promisify
is just a stop-gap.
Are there any differences in timing, queue priority, etc between process.nextTick
and await
?
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: https://github.com/nodejs/node/commit/329fc78e4919231bf76771797878f7b0db0f73ac
Are there any differences in timing, queue priority, etc between process.nextTick and await?
Are there any differences in timing, queue priority, etc between process.nextTick and await?
@timoxley All queued nextTick
s 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.
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
.
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.
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
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.
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): https://github.com/nodejs/node/issues/19426
It seems like discussion has exhausted itself.
If anyone feels strongly, feel free to reopen.
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?
Most helpful comment
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.