Detect asynchronous calls are finished, then trigger another function? - javascript

What is the best way to detect when all of my asynchronous calls are finished then trigger another function? I have three querys that are triggered by the user picking a topic. These querys run and their return values are then combined to be used in a new function. The problem is I need to know when they are all done then run the new function.
function queryHandler1() {
// do something
return result1;
}
function queryHandler2() {
// do something
return result2;
}
function queryHandler3() {
// do something
return result3;
}
function alldone(result1, result2, result3) {
// do something
return result4;
}
I have tried using jquery.when(), but it only runs the first time and when the user picks a new option it does not trigger alldone?
// global
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();
function queryHandler1() {
// do something
d1.resolve();
return result1;
}
function queryHandler2() {
// do something
d2.resolve();
return result2;
}
function queryHandler3() {
// do something
d3.resolve();
return result3;
}
function alldone(result1, result2, result3) {
// do something
return result4;
}
// the top level $.when
$.when(d1, d2, d3).done(function() {
alldone();
});
How do I reset the deferred or resolve so that all done is triggered again?
Thanks for the help!

You can use Async library
For your case you can use async.parallel or async.series
depending on wether you want to run your tasks simultaneously or sequentially
To use the library in the browser https://www.jsdelivr.com/package/npm/async

I solved this issue with what I think is an inelegant solution, but it works.
function queryHandler1() {
// do something
alldone();
}
function queryHandler2() {
// do something
alldone();
}
function queryHandler3() {
// do something
alldone();
}
var numCalls = 0;
function alldone() {
if (numCalls === 2) {
// do something
console.log("YES ALL DONE");
} else {
numCalls ++;
}
}
Any improvements?
Thanks

Related

How to reuse conditional check for each function?

I have many functions example like this
function update() {
if (isAdminUser()) {
return false;
}
...
}
function get() {
if (isAdminUser()) {
return false;
}
...
}
...
is there any possible way to have the conditional statement
if (isAdminUser()) {
return false;
})
written once and run by itself at the beginning of each function. I'm using javascript
You could use a higher order function to encapsulate the logic needed to run before a specific function is run. Higher order functions take functions as parameters, therefore a possible solution to your problem could look like this:
function withIsAdminUser(callback) {
return function() {
if (isAdminUser()) {
return false;
}
return callback();
}
}
function getRaw() {
// Do something here, this whole function could also be inlined
}
const get = withIsAdminUser(getRaw);
If you use TypeScript try decorators.
Docs: https://www.typescriptlang.org/docs/handbook/decorators.html#decorators
maybe you can define a function that can accept another function as an argument and returns false if that function (i.e isAdminUser in your code snippet) returns true
const checkUser = func => func() && false
then the function can be used like:
function update() {
if (checkUser(isAdminUser)) {
// update() logic will only run if user is not admin
}
}
function get() {
if (checkUser(isAdminUser)) {
// get() logic will only run if user is not admin
}
}

Stop a function running from ANOTHER function in JavaScript

What I want to do is stop a function running from ANOTHER function (in JavaScript). here is an example of what I would like to do:
async function process1(){ //this is a normal function running
//here is a long list of instruction that can take some time (~ 30s)
}
function STOPprocess1(){
process1().Stop; //this is pseudoCode !
}
When I call STOPprocess1() , I want the process1 function to stop running.
You could try something like this:
var flag = true;
async function process1(){ //this is a normal function running
while(flag){
await sleep(50); //we suppose we have the function sleep.
console.log("the function process1 is running...");
}
}
function STOPprocess1(){
flag = false;
}
But you may have problems with the scope...
Use a global variable to stop process 1
let isRunning = true;
async function process1(){ //this is a normal function running
while(isRunning){
await sleep(50); //we suppose we have the function sleep.
console.log("the function process1 is running...");
}
}
function STOPprocess1(){
isRunning = false;
}
How about using generator functions for that? If you yield, defer the call to .next() to a microtask, thus making it possible to interrupt:
function interruptable(gen) {
return function(...args) {
let timer, it = gen(...args);
function next() {
const { done } = it.next();
if(!done) timer = setTimeout(next, 0);
}
next();
return () => clearTimeout(timer);
};
}
const task = interruptable(function* () {
while(true) {
console.log("running");
yield;
}
});
const stop = task();
setTimeout(stop, 1000);
I would suggest setInterval over the use of a while loop (while(true) is generally frowned upon). You can then use clearInterval to stop execution.
let intervalId;
async function process1(){ //this is a normal function running
intervalId = setInterval(() => console.log("the function process1 is running..."), 50);
}
function STOPprocess1(){
clearInterval(intervalId)
}
while(true) might break your browser or whatever you're using. You can use setInterval() instead and use clearInterval() to stop the process.
//before starting the function
var process1;
//when starting the function
var process1 = setInterval(function() {
console.log("the function process1 is running...");
}, 50);
//to stop the function
function STOPprocess1(){
clearInterval("process1");
}
var cnt = 1;
var running = true;
process1();
async function process1(){
if(running){
await new Promise(resolve => setTimeout(resolve, 50));
document.getElementById("tstArea").innerHTML="this: "+ cnt;
cnt++;
process1();
}
}
function stopOtherFn(){
running = false;
}
<div id="tstArea">
</div>
<button onClick="stopOtherFn()">StopThat</button>
here is a rough mockup that seems to accomplish what you are looking for.
If you want to iterate something without stopping instead another function asks for it:
I would not do that. I believe every function should control itself. If the function dedicated to stop another function append to fail, the cost in term of ressources and time to fix it may become problematic.
Instead, I'd create a function calling another function after checking something else (cookie, data, variable).
const checkSomething = () => {
// var in parameter, cookie, data from API, etc
// if necessary throw new Error
if (something) return true;
return false;
};
const something = () => {
console.log('I did that');
};
const periodicallyDoSomething = () => {
try {
let continueDoingSomething = checkSomething();
while (continueDoingSomething) {
something();
continueDoingSomething = checkSomething();
}
} catch (e) {
console.error(e.message);
} finally {
console.log('I did it!');
}
};
// run it, or export it as in module.exports
If you want a function to do something that takes a lot if time while still being able to stop it externally, like a classic CTRL+C:
This should be inside your function.
I believe that a function dedicated to do something should be the same function finishing it.
Try/catch/finally, like I used it juste before, may be interesting.
Have a happy coding time. :)

javascript recursive class: undefined method

I have a JavaScript class that is meant to help deal with promises. First you add functions to an array, then it executes them pops them and calls itself to do the next one. At the end of the array it resolves that promise. My hope was to then propagate the resolution all the way up the stack of recursive calls. This will allow you to force multiple asynchronous functions to run sequentially using a simple set of commands. furthermore employ logic to modify the flow of the ansync functions.
function Sequencer() {
this.functionSequence = [];
this.addFunction = function (func) {
this.functionSequence.push(func);
}
this.getFunctionSequence = function () {
return functionSequence;
}
this.executeAll = function () {
var functionList = this.functionSequence;
var deferred = $q.defer();
if (functionList.length > 0) {
functionList[0]().then(function (result) {
if (result) {
functionList.splice(0, 1);
executeAll().then(function (resultInner) {
if (resultInner == true) {
deferred.resolve(true);
} else {
deferred.resolve(false);
}
});
} else {
functionList = [];
deferred.resolve(false);
}
});
} else {
deferred.resolve(true);
}
return deferred.promise;
}
}
I am getting ReferenceError: 'executeAll' is undefined
in this script, on the recursive call line "executeAll' just after the splice
the first function in the array is being executed(I was testing it with a modal pop up) and when it resolves it hits the splice, then it throws the error right on the executeAll line. Am I defining the function incorrectly? Am I calling it correctly as a recursive function?
use this.executeAll - assuming this will be correct, which it wont, so you'll need to account for that as well ... something like var self = this at the top of executeAll, then call self.executeAll
this.executeAll = function() {
var functionList = this.functionSequence;
var deferred = $q.defer();
var self = this; // save reference to this
if (functionList.length > 0) {
functionList[0]().then(function(result) {
if (result) {
functionList.splice(0, 1);
// need to use self here because "this" is not the "this" we want
self.executeAll().then(function(resultInner) {
if (resultInner == true) {
deferred.resolve(true);
} else {
deferred.resolve(false);
}
});
} else {
functionList = [];
deferred.resolve(false);
}
});
} else {
deferred.resolve(true);
}
return deferred.promise;
};
The reason this is not the this you "want" is due to how this works in javascript - there is plenty on info on stack exchange about using this - I'll find and link a good answer shortly
I offer this alternative code
this.executeAll = function() {
return this.functionSequence.reduce(function(promise, item) {
return promise.then(function(result) {
if (result) {
return item();
}
else {
throw "Fail"; // throw so we stop the chain
}
});
}, Promise.resolve(true))
.then(function(result) {
this.functionSequence = []; // clear out the added functions
return true; // fulfilled value is true as per original code
}.bind(this), function(err) {
this.functionSequence = []; // clear out the added functions
if (err == "Fail") {
return false; // convert the "Fail" to a fullfilled value of false as per original code
}
else {
throw err; // any other error - re-throw the error
}
}.bind(this))
};

Return JQuery.When deferred resolved

I have a function that include a function to an async function, but I need to return the first one when the async call has been resolved. I'm trying using
return JQuery.when()
The following function is a resume.
function getData(x){
if (x = 1){
return JQuery.when(asynFunction().then(function (data){
(...);
return;
});
}
else {
(...)
return;
}
}
The objective is that getData() doesn't return until the async call has finished.
Any idea?
Thanks for your time!
Assuming that asynFunction() returns a Promise, getData might, at its simplest, look like this :
function getData(x) {
if (x = 1) {
return asynFunction();
}
else {
var myValue = 'whatever';
return myValue;
}
}
However it's often better (though not absolutely necessary) to arrange for a function to return a Promise in all circumstances. This guarantees that wherever getData() is called, the result can be handled in an asynchronous manner (ultimately with .then or .done()) even if it is synchronously derived.
function getData(x) {
if (x = 1) {
return asynFunction();
}
else {
...
var myValue = 'whatever';
return jQuery.when(myValue);
}
}

Returning from a parent function from inside a child function - Javascript

I'm relatively new to coding in JavaScript, and I've came across a problem. I like to nest functions to keep things orderly, but how would I exit from a parent function from inside a child function?
example:
function foo1() {
function foo2() {
//return foo1() and foo2()?
}
foo2();
}
See update under the fold
You can't. You can only return from the child function, and then return from the parent function.
I should note that in your example, nothing ever calls foo2 (As of your edit, something does). Let's look at a more real example (and one that comes up a lot): Let's say we want know if an array contains an entry matching some criterion. A first stab might be:
function doesArrayContainEntry(someArray) {
someArray.forEach(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does <-- This is wrong
}
});
return false; // No it doesn't
}
You can't directly do that. Instead, you have to return from your anonymous iterator function in a way to stop the forEach loop. Since forEach doesn't offer a way to do that, you use some, which does:
function doesArrayContainEntry(someArray) {
return someArray.some(function(entry) {
if (entryMatchesCondition(entry)) {
return true; // Yes it does
}
});
}
some returns true (and stops looping) if any call to the iterator function returns true; it returns false if no call to the iterator returned true.
Again, that's just one common example.
You've referred to setInterval below, which tells me that you're almost certainly doing this in a browser environment.
If so, your play function almost certainly has already returned by the time you want to do what you're talking about, assuming the game has any interaction with the user other than alert and confirm. This is because of the asynchronous nature of the environment.
For example:
function play() {
var health = 100;
function handleEvent() {
// Handle the event, impacting health
if (health < 0 {
// Here's where you probably wanted to call die()
}
}
hookUpSomeEvent(handleEvent);
}
The thing is, that play will run and return almost immediately. Then the browser waits for the event you hooked up to occur, and if it does, it triggers the code in handleEvent. But play has long-since returned.
Make a note whether the parent function should also return.
function foo1() {
bool shouldReturn = false;
function foo2() {
shouldReturn = true; // put some logic here to tell if foo1() should also return
return;
}
if (shouldReturn) {
return;
} else {
// continue
}
}
It only says that you can't return the parent function in the child function, but we can do a callback and make it happen.
function foo1(cb = () => null) {
function foo2() {
cb();
}
foo2();
}
foo1(() => {
// do something
});
We can use Promises for this:
const fun1 = async () => {
const shouldReturn = await new Promise((resolve, reject) => {
// in-game logic...
resolve(true)
})
if(shouldReturn) return;
}
if you wanna return from the parent function, then just resolve with true
Based on your comment, something like this might work as a main game loop.
function play() {
var stillPlaying = true;
while(stillPlaying) {
... play game ...
stillPlaying = false; // set this when some condition has determined you are done
}
}

Categories