How to execute javascript functions synchronously - javascript

I am newbie in nodejs. Can some write me a sudo code that does the following?
Function1(); //returns an array which can be used in function2 and function3
Function2(); //returns an array which can be used in function3
Function3();
I want to run all three functions synchronously.
So function2 has to wait for function1 to finish, then use the returned array in the function2. Then function3 waits for function2 to finish, then use the returned array in the function3 and so forth.
Tried something like this but then seems execute at the same time as well.
function main() {
return Promise.resolve()
.then (function(){
function1()
})
.then (function(){
function2()
})
.then (function(){
function3()
})
}

This might be able to help you out:
function main() {
return Promise.resolve()
.then (function(){
return function1()
})
.then (function(results){
// process your results
return function2([pass arguments IF required])
})
.then (function(results){
// process your results
function3([pass arguments IF required])
})
.then (function (results) {
return results
})
.catch(function(err) {
console.log(err)
})
}
So in short what you're missing out is returning the function value which is to be captured and used by next then.

Example where each of the functions returns a promise that resolves with the return of an array which gets passed to next function where each element in array gets multiplied by 10
Starting with [1,2,3] getting passed to function2 becomes [10,20,30] which gets passed to function3 and becomes [100,200,300]
function asynchFake(data){
return new Promise((resolve)=>{
setTimeout(()=> resolve(data),1000)
})
}
function func1(){
console.log('func1')
return asynchFake([1,2,3])
}
function func2(func1Data){
console.log('func2')
return asynchFake(func1Data.map(v=>v*10));
}
function func3(func2Data){
console.log('func3')
return asynchFake(func2Data.map(v=>v*10))
}
function main() {
console.log('main')
return func1().then(func2).then(func3)
}
main().then(res=>console.log('final results', res))

You could also try async/await to make the three functions run synchronously:
function function1(){
return [1]
}
function function2(arr){
return arr.concat([2])
}
function function3(arr){
return arr.concat([3])
}
async function main(){
let res = await function1(); // waits for function1 to complete before moving to the next line
let res2 = await function2(res); // similarly waits for the completion of function2
let res3 = await function3(res2); // similarly waits for the completion of function3
console.log(res3)
console.log("end of main")
}
main()

here are 2 ways you can achieve what you are looking for. It was a bit trickier as you were using two different functions, but I think I got what you are looking for.
Utilize a callback function
Utilize the node event emitter

There are 2 ways you can achieve what you are looking for.I think I got what you are looking for.
Utilize a callback function
Utilize the node event emitter.

Related

.then() doesn't wait till async function resolves promise?

I have two functions. First contains jQuery.get().done() and it's return value is inside done() callback function, as showed below. (I have no idea if using jQuery matters here)
I may not be understanding something, but my functions looks similar to those in first w3 example: https://www.w3schools.com/js/js_async.asp
async function A(){
jQuery.get("example.com").done(function(result){
if (result.indexOf("Example")){
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
})
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
But the output is:
Res:undefined
// here some time passes for A() to complete.
succes
So I can't understand why .then() doesn't wait for function A() to complete and resolve promise, but instead it acts immediately while result is not defined yet ?
This is much better written using actual promises (which jQuery supports) and await as follows:
async function A() {
const result = await jQuery.get("example.com");
if (result.indexOf("Example") !== -1) {
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
}
Notes:
Stop using jQuery's .done(). It's non-standard. Use .then() or await.
Don't mix await with .done() or with .then(). Use one model or the other.
There's no need for the res intermediate variable. When you get rid of the .done(), you can just return the value directly.
Note, .indexOf() does not return a boolean. It returns -1 if not found and an index of the position if found. Best not to treat its return value as a boolean.
This isn't really a jQuery thing in particular. It's just async JS in general. I'm not sure you really need the .done() part at all since you're using promises.
But anyway, you have two basic problems.
You need to return something inside of function A, not inside .done(). So you can return jQuery.get().
In function B, you want to wait for function A to complete before hitting the .then() block. That means function B is also async. (In the simple example below you can omit the async keyword on function A.) You need to declare function B as async and then await the completion of function A.
 
function A() {
return jQuery.get("example.com").done(function(result) {
if (result.indexOf("Example")) {
console.log("sucess", result);
} else {
console.log("Fail", result);
}
});
}
async function B() {
await A().then(function(result) {
console.log("Res:");
// moved to a separate console log, otherwise dev tools might print
// a lot of [objectObject] instead of the actual result
console.log(result);
})
}
B();
If you want to do other stuff inside of function A and then eventually return the result, you can play around with something more like
async function A() {
const response = await jQuery.get('example.com');
// more stuff…
return response;
}
I fixed it by moving return statement outside from the .done(function(){}) and by adding await before jQuery chain. And instead of returning value inside that callback function, now I only pass there value to variable, which is later returned outside of that callback function.
async function A(){
let res = 0;
await jQuery.get("example.com").done(function(result){ //await was added
if (result.indexOf("Example")){
console.log("sucess");
res = 1; // value is passed to variable, which is returned as result outside this callback function
} else {
console.log("Fail");
res = -1;
}
})
return res; // return statement is outside the callback function
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
I guess the problem was, as #cjl750's answer says, that return statement inside the callback function isn't "seen" as a "true return statement" of that function. So function B() probably saw function A() as a function, which doesn't return anything.
EDIT
I've rewritten the code using $.Deferred() object. It's probably better now. Await is now moved to function B(), it doesn't wait for jQuery chain anymore.
function A(){
var dfd = $.Deferred();
jQuery.get("google.com").then(function(result){
if (result.indexOf("Example")){
console.log("sucess");
dfd.resolve(1);
} else {
console.log("Fail");
dfd.resolve(-1);
}
})
return dfd.promise();
}
async function B(){
await A().then(function(result){
console.log("Res:" + result);
})
}
B();

Despite Await the function is being executed instantly

I am new to Javascript and am facing trouble dealing with Async/Await. Here is my code, as per my understanding adding await puts on hold the function
Here, inside foo, it should put on hold the code at checker() and move to running the commands outside foo, but instead it executes the checker() function before console.log('the end').
function checker() {
console.log('inside checker');
return "Ok"
}
async function foo() {
let a = await checker(); // Shouldn't using await here let next line outside foo to execute
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
// Output coming is:
//1
//inside checker
//the end
//mid Ok
Can someone please tell me what properties are making it to behave this way. I know there's something that I am missing but can't figure out what.
Your checker function is not asynchronous, but you also need to do something that is actually async within it.
At the moment, all of the promises are instantly resolved which provides no opportunity for later code to run.
We need to actually create a promise, merely defining a function as async isn't enough unless something inside is returning a promise, so we return a new promise which is resolved by the setTimeout callback.
Note that the timeout period is 0 which is enough to cause the javascript event loop to be invoked, which allows the next statement(s) after calling foo to be processed. Changing this to any positive integer will change the execution time but not the order of events.
function checker() {
return new Promise(resolve => {
setTimeout(() => resolve('Ok'), 0)
})
}
function foo() {
let a = checker();
console.log(new Date(), "mid");
return a
}
(async () => {
console.log(new Date(), 'start');
foo().then(v => console.log(new Date(), 'eventually', v));
console.log(new Date(), 'the end');
})()
You didn't define your function as async
function checker() {
console.log('inside checker');
return "Ok"
}
It should be
async function checker() {
console.log('inside checker');
return "Ok"
}
await tells your code to wait for the function to finish. If you want to continue running without waiting, then you shouldn't use the await keyword. async also needs to be on the function that you want to run asynchronously, in this case checker()
async function checker() {
console.log('inside checker');
return "Ok"
}
function foo() {
let a = checker();
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
foo is an async function, ie the code inside it will wait if you use the await keyword
But the foo function returns a promise. so if you want to wait for foo either use
await foo();
or use
foo().then(() => { console.log('the end'); })

Passing a function to Promise.then results in a different behaviour than passing a nested function

The following code
function doSomething(msg){
return new Promise((resolve, reject) => {
setTimeout(
() => {
console.log(msg);
resolve();
},
2000);
})
}
let start = Date.now();
let end;
doSomething("1st Call")
.then(()=>doSomething("2nd Call"))
.then(()=>doSomething("3rd Call"))
.then(()=>{
end = Date.now();
console.log('start',start);
console.log('end',end);
console.log('elapsed time',end-start);
})
prints 1st Call, 2nd and 3rd, with 2 seconds between each console.log statement, as expected
However, if I remove the arrow functions from the then blocks, the behaviour is totally different, i.e
doSomething("1st Call")
.then(doSomething("2nd Call"))
.then(doSomething("3rd Call"))
.then(()=>{
end = Date.now();
console.log('start',start);
console.log('end',end);
console.log('elapsed time',end-start);
})
With this code, all the console.log statements get printed at the same time, and the elapsed time is just 2 seconds, as opposed to 2 seconds per function (6 seconds total as in the first example)
In other words, for the code to work correctly, the then function needs to take a function (the arrow one in this case), and from inside that function, then I can do further function calls.
Why can't I just pass the function directly, why does it need to be nested in another function?
.then() expects a callback function which will be called when the Promise on which .then() method is called - fulfills.
When you do this
.then(doSomething("2nd Call"))
instead of registering a callback function which will be invoked at some later time, doSomething() is called immediately.
You could pass a reference to a function to the .then() method and .then() will call that function when Promise fulfills.
.then(doSomething)
but you won't be able to pass any argument to doSomething function.
.then(doSomething("2nd Call")) will only work if doSomething returns a function. In that case, returned function will be registered as a callback and will be called when Promise fulfills.
You could use .bind() to get a function which will be used as a callback to .then() method
function doSomething(msg){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(msg);
resolve();
}, 2000);
});
}
let start = Date.now();
let end;
doSomething("1st Call")
.then(doSomething.bind(null, '2nd Call'))
.then(doSomething.bind(null, '3rd Call'))
.then(()=>{
end = Date.now();
console.log('start',start);
console.log('end',end);
console.log('elapsed time',end-start);
})
If you use then(fn()), it will not return a value for the next .then(...) to use, so it can continue immediately.
When you use .then(variable => fn()), the next .then(...) will wait for the first to resolve or reject.
It's similar to the difference between the functions
function a () {
stuff
}
function b (){
return stuff
}

How to defer long-time simple function?

I create microservice and in one function I have three other functions, for example:
functionA();
functionB();
functionC();
return json({status: processed});
All functions are synchronous, but they execute Math operations. functionB is the longest performed, so I would like to use it as for example HTTP request, which is asynchronous.
I tried:
functionB() {
return new Promise(//etc...);
}
and
async functionB() {
return 1;
}
but my function still is synchronous.
How does Node recognize which function can be run immediately or should go to event loop? Why Promise and async not working in this case?
This logs 'foo' then 'bar'
function foobar() {
var p = Promise.resolve();
p.then(() => console.log('bar'));
console.log('foo');
return p;
}
While this logs 'bar' then 'foo'.
function foobar() {
var p = new Promise((resolve, reject) => {
console.log('bar');
resolve();
})
console.log('foo');
return p;
}
This is because the callback (resolve, reject) => ... passed to new Promise is called immediately as part of the promise creation process, thus the callback is actually a sync function.
Similarly with async function.
async function B() {
return 1;
}
Marking a sync function async doesn't magically make it "async". If the function body (return 1 in this example) consists of all synch operations, then it is the same as the callback passed to new Promise, it's still executed synchronously when called.
If you really need to defer the task to next loop iteration, use setTimeout(cb) or setImmediate(cb) is more promising. That cb is async for sure.

Chain multiple AJAX calls with delay and passing variables

I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop

Categories

Resources