As a simplified case, I have two async functions, foo
and bar
. bar
needs the result of foo
, i.e. bar
depends on foo
. I have no idea about which function will be called first.
bar
is invoked first, bar
will call foo
and start itself right after foo
is done.foo
is invoked first and done, bar
can use the result of foo
.foo
is invoked first and bar
is invoked before foo
is done, bar
needs to wait for foo
's result. (Don't invoke a new call to foo
, just wait for the already-fired call to foo
)How can I achieve this?
Is it possible to register an async function dependency chain (something like the dependency in require.js define['foo'], function() { bar(); }
)?
Can I use $.deferred()
to achieve it?
How?
JavaScript provides three methods of handling asynchronous code: callbacks, which allow you to provide functions to call once the asynchronous method has finished running; promises, which allow you to chain methods together; and async/await keywords, which are just some syntactic sugar over promises.
To detect if a function is asynchronous, use the function's constructor.name property: const isAsync = myFunction.constructor.name === "AsyncFunction"; If the value is AsyncFunction , you know the function is async !
JavaScript Async FunctionsAsync and await are built on promises. The keyword “async” accompanies the function, indicating that it returns a promise. Within this function, the await keyword is applied to the promise being returned. The await keyword ensures that the function waits for the promise to resolve.
In circumstances like this, the standard approach is to cache the lower level promise.
Typically you will establish, in some suitable outer scope, a js plain object as a promise cache, and always look there first before calling your async process.
var promiseCache = {};
function foo() {
if(!promiseCache.foo) {
promiseCache.foo = doSomethingAsync();
}
return promiseCache.foo;
}
function bar() {
return foo().then(doSomethingElseAsync);
}
Of course, there's nothing to prevent you also caching the higher level promise, if appropriate.
function bar() {
if(!promiseCache.bar) {
promiseCache.bar = foo().then(doSomethingElseAsync);
}
return promiseCache.bar;
}
EDIT: forceRefresh
feature
You can force a function to refresh its cached promise by passing an (extra) parameter.
function foo(any, number, of, other, arguments, forceRefresh) {
if(forceRefresh || !promiseCache.foo) {
promiseCache.foo = doSomethingAsync();
}
return promiseCache.foo;
}
By making forceRefresh
the last argument, leaving it out is the same as passing false
and foo
will use the cached promise if available. Alternatively, pass true
to guarantee that doSomethingAsync()
be called and the cached value be refreshed.
EDIT 2: setName()/getName()
With the forceRefresh
mechanism in place in getName()
:
setName(newName).then(getName.bind(null, true)); //set new name then read it back using forceRefresh.
Alternatively, omit the forceRefresh
mechanism and, assuming the cache property to be promiseCache.name
:
setName(newName).then(function() {
promiseCache.name = $.when(newName);//update the cache with a simulated `getName()` promise.
});
The first method is more elegant, the second more efficient.
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