Javascript
Grunt, Gulp, CoffeeScript, IIFE, overridden undefined, with, closures to create private fields, modified prototypes, variables global by default, call-site-this, automatic conversions for comparisons… Ah yes, over a decade of JS.
Microtasks
Runtime order
Promises run after synchronous code, but before the start of the next full event-loop cycle.
Promise.resolve(42).then(() => console.log("From promise"))
setTimeout(() => console.log("From setTimeout"), 0)
console.log("From bare console log")
Outputs:
From bare console log
From promise
From setTimeout
This isn’t a race condition, this behavior is defined in the ECMAScript spec.
Finish running all pending promises before continuing
This function returns a promise that will only resolve at the beginning of the next event-loop cycle, after all code that depends on resolved promises has run.
This is mostly useful in unit testing when you’ve mocked an interface to return Promise.resolve(some_result)
and you want to assert what happens next.
// Finish running all current promises before continuing
function flushPromises() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
});
});
}
// usage
await flushPromises();
try/finally
blocks Curiosity
Competing returns
function f() {
try {
return "foo";
} finally {
return "bar";
}
}
Will return "bar"
continue
in a finally
block
This will act as a bizzare infinite loop. The continue
in the finally
block will “win” over the return.
function f() {
while (true) {
try {
return "foo";
} finally {
continue;
}
}
}
f();
Adding a let
variable can be a breaking change for code above it Curiosity
With no declaration:
console.log(typeof foo); // undefined
With a let
declaration:
console.log(typeof foo); // ReferenceError: can't access lexical declaration 'foo' before initialization
let foo = 50;