Consider the following code, and how it can be affected by the following transformations:
function foo () {
return {x: 5}
}
foo() === foo() // => false
This function is statically compiled away by supporting transformers (which need to have esprima/acorn-level knowledge about scope and the like). Otherwise, it should either NOOP or error. The idea is that any expressions wrapped in loadTimeValue
are yanked out into a module-level cache, and evaluated only once -- at the top level (so they don't see local function scope!), and a reference into that cache is inserted into the original callsite.
Thus, consider then the effect of using loadTimeValue
in the base code:
function foo () {
return loadTimeValue({x: 5})
}
This would be transformed into code like:
const __LOAD_TIME_VALUES__ = [
{x: 5}
]
function foo () {
return __LOAD_TIME_VALUES__[0]
}
Which, would yield a different result in the expression we evaluated:
foo() === foo() // => true
Now consider the more familiar use of function inlining, assuming the ability to explicitly do so for existing functions:
function foo () {
"inline";
return {x: 5}
}
Our original function would be extracted entirely, but our evaluated expression would transform into:
{x: 5} === {x: 5} // => false
Inlining is fairly familiar, of course, and stuff like loadTimeValue
is done manually all the time. But what about when we combine both?
function foo () {
"inline";
return loadTimeValue({x: 5})
}
foo() === foo() // => false
Ideally, we would first transform "inline";
declarations away, leaving us with only this code:
loadTimeValue({x: 5}) === loadTimeValue({x: 5})
And the ltv
would be replaced in the following pass, leaving us with:
const __LOAD_TIME_VALUES__ = [
{x: 5},
{x: 5}
]
__LOAD_TIME_VALUES__[0] === __LOAD_TIME_VALUES__[1] // false
The examples here were more meant to show the mechanics involved, but in practice, both of these can turn out to be tremendously useful. Put together, they make it trivial to add general or inline caching to any similar values!
function timesCalled () {
"inline";
var counter = loadTimeValue({count: 0})
return ++counter.count
}
function caller() {
if (randomTruthy()) {
console.log('callsite #1 calls: ', timesCalled())
} else {
console.log('callsite #2 calls: ', timesCalled())
}
}
repeat(100, caller) // Prints different counts depending on how `randomTruthy` goes