Many times, I needed to write such a lazy asynchronous loading in Javascript:
if (myvar != undefined){
doSomeTreatment(myvar)
} else {
loadMyVarAsynchronously().then(function(value){
myvar = value
doSomeTreatment(myvar)
})
}
Here, myvar would be some attribute of a hash, not a local variable. loadMyVarAsynchronously
loads asynchronously the value for myvar (with, for example, a Promise
or a JQuery Deferred
)
Is there a pattern to avoid having to write twice the following line in this code?
doSomeTreatment(myvar)
If myvar
is already defined you can pass that into $.when()
and have it automatically wrapped into a resolved promise:
var def = (myVar !== undefined) ? myVar : loadMyVarAsynchronously();
$.when(def).then(doSomeTreatment);
Make the assignment to myVar
inside doSomeTreatment()
, if required, instead of inside the anonymous .then
callback, this allows you to pass doSomeTreatment
directly as a function reference.
EDIT oops, did you want standard Promises, or jQuery promises? The above is jQuery style.
It's really hard to reason about what you are doing here without a concrete, real-world example. This is definitely not a pattern I use a lot in my code so I have a suspicion that you could go around fixing it by re-assessing your assumptions.
That being said, you can use promise chaining. Note in this case promiseThatLoadsVar IS a promise, it's not a function that returns a promise. That means it maintains a state, and the second time this code runs onward it will return immediately.
promisethatLoadsVar.then(function(value) {
myvar = value;
doSomeTreatment(myvar);
})
If you could give a clearer question I'd love to provide a clearer answer for you.
Edit: I want to elaborate on the example posed in the comments. Here is a solution using the LoDash library. (BTW, you should use lodash or underscore, they are basically the standard library of javascript).
var getData = _.once(function() { return $.getJSON(...) });
$('button').on('click', function() {
getData().then(function(data) { showDialog(data) })
})
Note here that getData
is a wrapped function that after the first invocation will just return the same thing over and over without re-invoking the function. The first time you invoke it, it will return a promise that resolves when data is retrieved. The second time onward you get back the same promise which will likely already be resolved.
Do you want to pass in parameters to getData
?
var getData = _.memoize(function(id) { return $.getJSON(url+id) });
$('button').on('click', function() {
getData($('#selector').val()).then(function(data) { showDialog(data) })
})
This will do the same thing, but cache the promises by the first input parameter passed to getData
.
Yes, you should build a promise for the value. Then you just need to attach that function only once as a handler:
var loadedMyVar = myvar!=undefined ? Promise.resolve(myvar) : loadMyVarAsynchronously();
loadedMyVar.then(doSomeTreatment);
Oh, and you shouldn't need to reassign to myvar
asynchronously, just use the loadedMyVar
promise everywhere. Maybe even use
var loadedMyVar = loadedMyVar || loadMyVarAsynchronously();
loadedMyVar.then(function(value) {
return myvar = value;
}).then(doSomeTreatment);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With