Defer expression
Deferring can mean different things, but generally then
covers this well
(specifically, pushing execution of something to the end of the current
task).
Promise.resolve().then(stuffToDefer);
I think there is a proposal for Promise.try(stuffToDefer)
, which would eliminate the need for the resolve
bit.
Promise.try
calls its callback synchronously like new Promise
does, so
it would not be a substitute for this case.
I believe this is the most recent on this topic: esdiscuss.org/topic/microtask-scheduling
-- T.J. Crowder
@logan ah, oops, that was an (incorrect) assumption about the proposed behavior on my part
I think this will actually get you what you're after:
(async function () {
await null; // Deferred code here
})()
On Aug 16, 2017 5:46 PM, "Darien Valentine" <valentinium at gmail.com> wrote:
@logan ah, oops, that was an (incorrect) assumption about the proposed behavior on my part
setTimeout is still the best solution in my mind. none of the promise or async code examples presented are as immediately obvious as setTimeout that the code is to self-run at a later time (and you don't need the 1ms argument).
// self-comment that this code will self-run
// after the main script in a reasonably immediate fashion
setTimeout(function () {
// deferred code
})
An in built Promise
version of setTimeout
would be cool:
Promise.delay()
and Promise.delay(500)
setTimeout
it is defined in the HTML spec,
www.w3.org/TR/html5/single-page.html#timers, not the ECMA spec. The
ECMA spec has no concept of time-based delays at all, promise-based or
otherwise.
Honestly have there been any proposals for something like do async { // can await here }
which would produce a promise in the enclosing scope
- Matthew Robb
On Thu, Aug 17, 2017 at 12:12 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:
Honestly have there been any proposals for something like
do async { // can await here }
which would produce a promise in the enclosing scope
Do-expressions haven't advanced in general yet, but if/when they do,
this seems like it might be reasonable. It's just sugar for the
Promise.resolve().then(()=>{...})
expression, right?
Yeah essentially although I'd think of it more as sugar for:
(async () => { await null; ... })()
i can give you a specific solution to one of my async init problems (done entirely in vanilla es5 code). in this use-case, i want to run integrated tests, but have to wait for the server to listen on a port, and the db to be seeded first. to keep complexity at a manageable level, i find its worth the tradeoff to pollute the global namespace with initialization functions and counters, especially if you intend to break up the below example into separate modules.
global.initializationCounter = 0;
global.initializationCounterDecrement = function () {
/*
* this function will decrement the initialization counter,
* and if the initialization counter reaches zero, then run the post-init code
*/
global.initializationCounter -= 1;
if (global.initializationCounter === 0) {
global.postInit();
}
};
global.postInit = function () {
/*
* run your custom post-init code here
*/
// run test-runner after initialization
global.testRun();
};
...
var db, http, server;
http = require('http');
// pre-init1 - create http server,
// and wait for server to listen to port 8080, before running post-init code
server = http.createServer(function (request, response) {
// request handler
...
});
global.initializationCounter += 1;
server.listen(8080, global.initializationCounterDecrement);
// pre-init2 - create db,
// and wait for db to seed, before running post-init code
db = ...;
global.initializationCounter += 1;
db.insert(<data1>, global.initializationCounterDecrement);
global.initializationCounter += 1;
db.insert(<data2>, global.initializationCounterDecrement);
// pre-init3 - any extra async init code
global.initializationCounter += 1;
setTimeout(function () {
// you custom code
...
global.initializationCounter();
});
Closer to the proposed Promise.try
, in that it starts synchronously.
Also, normal do
expressions are stage 1 currently, and the core concept
hasn't changed much in the several years of the proposal's existence. (It's
based on statement completion values, like eval
.)
kai zhu has a good example of solving async order problems explicitly, as opposed to banking on any defer or timeout to figure it out.
I'm a little curious of what you mean by "something that cannot run immediately".
If it can't be run immediately, then there should be something you can hook into to run -- otherwise you're playing guesswork on what is currently scheduled to execute.
Examples of the arbitrary use of "setTimeout" to defer to another script frame in the DOM is when a frontend framework hasn't created elements yet, and you need to run a query selector to grab them, or similar shenanigans.
I'd argue more that these are all anti patterns, since why should you be guaranteed that toDoLater() can even be run after the setTimeout(1) or when the Promise scheduler runs?
is there any proposal for an expression to invoke something after the current call stack has cleared? Lodash
defer
is a good example.Just like I can use
await
to pause the execution of the current call, it would be nice to also have an expression to queue up something that cannot run immediately e.g.defer doThisLater();
The current solution is to use
setTimeout
with a 1 ms delay but that is not a good solution as it is not the same thing and it makes it more difficult for people to understand what is the true purpose of that line of code.