Wait for a functions to finish in sequence Javascript - javascript

I have three functions prints 20,30,10 as per setTimeout how should i make them print 10,20,30 order using promise
How to write these callbacks to print right order.
P.S. : This is not a duplicate question. Thanks !
var A = function(callback) {
setTimeout(function() {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20);
callback();
};
var C = function(callback) {
setTimeout(function() {
console.log(30)
callback();
}, 200);
};
function runTask() {
var wait = ms => new Promise ((resolve,reject) => setTimeout(resolve, ms))
var FuncA = wait();
FuncA.then(() => A(function () {}))
. then(() => B(function () {}))
.then(() => C(function () {}));
}
runTask();

I'm not 100% sure I understood your question. But, here it is based on what I understood. You weren't doing anything with the callback so I didn't pass them.
In your code function B didn't have a delay.
function delayAsync(ms) {
return new Promise(p_resolve => setTimeout(p_resolve, ms));
}
async function A(callback) {
await delayAsync(2000);
console.log(10);
if (callback instanceof Function) {
callback();
}
}
async function B(callback) {
console.log(20);
if (callback instanceof Function) {
callback();
}
}
async function C(callback) {
await delayAsync(200);
console.log(30);
if (callback instanceof Function) {
callback();
}
}
function runTask() {
return new Promise(async (resolve, reject) => {
await A();
await B();
await C();
resolve();
});
}
runTask().then(() => console.log('done'));

If you want to stick with Promises, you could create a helper function that performs a setTimeout but returns a Promise. This will preserve the order of console logs:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
function runTask() { // refactored since A now returns a Promise
return A(() => {})
.then(() => B(() => {}))
.then(() => C(() => {}));
}
runTask();
Alternatively, if you'd like a clean solution and don't mind adding a third party module, you could use async-af, a library for chainable asynchronous JavaScript methods that I maintain:
const setTimeoutAsync = (fn, ms) => new Promise(resolve => setTimeout(() => resolve(fn()), ms));
var A = function(callback) {
return setTimeoutAsync(() => {
console.log(10)
callback();
}, 2000);
};
var B = function(callback) {
console.log(20)
callback();
};
var C = function(callback) {
return setTimeoutAsync(() => {
console.log(30)
callback();
}, 200);
};
// to run in parallel you would omit `series`, but
// since you want to run the tasks in order include it:
function runTask(...tasks) {
return AsyncAF(tasks).series.forEach(task => task(() => {}));
}
runTask(A, B, C);
<script src="https://unpkg.com/async-af#7.0.11/index.js"></script>

Related

Proper use of async JS to ensure function calls wait for previous functions to complete (resolve?)

Trying to learn proper async/await JavaScript to run functions in sequence when an early function in the sequence would be delayed (using setTimeout to simulate). I'm not getting the expected results (still getting "first", "second", "this should run first?" - see code).
What am I missing? Do I have the wrong idea about this?
Thanks in advance!
const zeroFunction = () => {
setTimeout(() => {
return new Promise((resolve) => {
console.log("This should run first?");
resolve();
});
}, 2000)}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first");
resolve();
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second");
resolve();
})
}
async function fnAsync() {
await zeroFunction();
await firstFunction();
secondFunction();
}
fnAsync();
zeroFunction is currently returning undefined implicitly, not a Promise. Inverse the wrapping of the setTimeout and Promise constructor and it should work as expected.
const zeroFunction = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log("This should run first?")
resolve()
}, 2000)
})
}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first")
resolve()
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second")
resolve()
})
}
async function fnAsync() {
await zeroFunction()
await firstFunction()
secondFunction()
}
fnAsync()

how can we combine synchronous function, callback function and promise all together

If I have three types of functions, which return, respectively,
A synchronous value:
function a(){
return 'a';
}
A callback:
function b(callback){
setTimeout(() => {
callback('b');
}, 10);
}
a Promise:
function c() {
return Promise.resolve('c')
}
How can I combine the result of all 3 in a single promise? Can I create a function which will return ['a', 'b', 'c']? I do not want to change these three functions.
How can we combine a synchronous function, a callback function and a Promise all together?
Promisify the callback, and send all three through Promise.all.
function a() {
return "a";
}
function b(callback) {
setTimeout(() => {
callback('b');
}, 10);
}
const bProm = () => new Promise(b);
function c() {
return Promise.resolve('c')
}
Promise.all([
a(),
bProm(),
c(),
])
.then((results) => {
console.log(results);
});
Given the functions:
function a(){
return 'a';
}
function b(callback){
setTimeout(() => {
callback('b');
}, 10);
}
function c() {
return Promise.resolve('c');
}
You can wrap them all in a promise using Promise.all(). The solution will depend on your requirements and limitations.
The function b(callback) must be wrapped, or be changed to accomplish this, because it has a setTimeout within it.
Wrapped version
function bWrapped (callback) {
return new Promise(
resolve =>
b(()=> {
resolve(callback('b'));
}
)
}
A function to return the expected result would be like:
const abc = () => {
const functionAPromise = Promise.resolve(a())
const callback = function(b){return b}
const functionBPromise = bWrapped(callback)
return Promise.all([functionAPromise,functionBPromise,c()])
}
Changed version
function b(callback){
return new Promise(resolve => setTimeout(()=> resolve(callback('b')), 10))
}
A function to return the expected result would be like:
const abc = () => {
const functionAPromise = Promise.resolve(a())
const callback = function(b){return b}
return Promise.all([functionAPromise,b(callback),c()])
}
Just check the result of each function and handle them.
function a() {
return "a";
}
function b(callback) {
setTimeout(() => callback("b"), 10);
}
function c() {
return Promise.resolve("c");
}
const functionList = [a, b, c];
function runFunctionList(list, callback) {
const resultList = [];
const called = {};
function next() {
if (resultList.length === list.length) {
for (let i = 0; i < resultList.length; i++) {
if (resultList[i] === undefined) {
return;
}
}
callback(resultList);
resultList.length = 0;
}
}
list.forEach((li, index) => {
const ret = li(value => {
resultList[index] = value;
next();
});
if (ret instanceof Promise) {
// it's promise
ret.then(value => {
resultList[index] = value;
next();
});
} else if (ret === undefined) {
// it's callback function
} else {
// it's synchronous function
resultList[index] = ret;
}
});
next();
}
runFunctionList(functionList, allValue => {
console.log("allValue here:", allValue);
});
Sequential execution:
function a() {
return 'a';
}
function b(callback) {
setTimeout(() => {
callback('b');
}, 10);
}
function c() {
return Promise.resolve('c');
}
function abc() {
return new Promise(resolve => {
const valueA = a();
b(valueB => {
c().then(valueC => {
resolve([valueA, valueB, valueC]);
});
});
});
}
abc().then(result => {
console.log(result);
});

Returning another aysnc function in resolve

I have a function call like so:
await someFunction(foo);
With someFunction defined like:
const someFunction = foo => {
return new Promise((resolve, reject) => {
if (foo) {
return resolve(someOtherPromise());
}
reject();
}
}
Is this valid code? I have tested it and it seems ok.
Is it correct that await someFunction() will transform to await someOtherPromise() if foo is true i.e. will it continue waiting for someOtherPromise to resolve?
Yes, it is valid code and works by resolving with a promise, but smells like the Promise constructor antipattern. I would instead recommend to write
function someFunction(foo) {
if (foo)
return someOtherPromise();
else
return Promise.reject();
}
or
async function someFunction(foo) {
if (foo)
return someOtherPromise();
else
throw;
}
(and better throw a new Error with a message, not undefined)
I've written some test code to see if it's true:
const someFunction = foo => {
return new Promise((resolve, reject) => {
if (foo) {
return resolve(someOtherPromise(2000));
}
reject();
});
}
const someOtherPromise = async(ms) => {
return new Promise(resolve => setTimeout(() => {
console.log("i'm about to resolve in someOtherPromise");
resolve();
}, ms));
}
const run = async () => {
await someFunction('foo');
console.log('finished waiting for someFunction');
}
run();
I have written 3 function to test it out.
c = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('c');
resolve();
}, 1000);
});
b = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('b');
resolve(c());
}, 1000);
});
a = async () => {
console.log('a before');
await b();
console.log('a after');
};
a();
As we can see, the output order is a before, b, c then a after. So await had waited for b and continued waiting for c.

2 functions on Promise chaining are being called asynchronously

I am learning javascript Promise. I have created 2 independent functions and am chaining them in a promise function. However the second function gets called first even though it is in the second then() block.
Code is below.
const one = document.getElementById('one');
function clkw(a){
setTimeout(() => {
one.innerHTML = a;
return 2*a;
}, 2000);
}
function clkw2(b){
setTimeout(() => {
one.innerHTML += ' '+b;
}, 2000);
}
function trypromise(){
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data){
return clkw(data);
})
.then(function(bata){
clkw2(bata);
});
}
If you want to chain and still be able to execute async code in the then continuation, you have to return a promise that resolves only when the result is ready.
In your snippet you don't actually return any values (or promises) from chained thens that can be used down the pipeline. Because of that, the result is automatically converted to a resolved promise that doesn't have any value.
const one = document.getElementById('one');
function clkw(a){
return new Promise(res => {
setTimeout(() => {
one.innerHTML = a;
res(2*a);
}, 2000);
});
}
function clkw2(b){
return new Promise(res => {
setTimeout(() => {
one.innerHTML += ' '+b;
res();
}, 2000);
});
}
function trypromise(){
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data){
return clkw(data);
})
.then(function(bata){
clkw2(bata);
});
}
trypromise();
<div id='one'></div>
However the second function gets called first even though it is in the second then() block.
Everything works as expected in the code you provided. How did you observe the strange behavior?
const one = document.getElementById('one');
function clkw(a) {
console.log("clkw");
setTimeout(() => {
one.innerHTML = a;
return 2 * a;
}, 2000);
}
function clkw2(b) {
console.log("clkw2");
setTimeout(() => {
one.innerHTML += ' ' + b;
}, 2000);
}
function trypromise() {
const np = new Promise(resolve => {
setTimeout(() => {
resolve(10)
}, 2000);
});
np
.then(function(data) {
return clkw(data);
})
.then(function(bata) {
clkw2(bata);
});
}
trypromise()
<div id="one"></div>

async and await for calling couple of setTimeout in order

If I have this two variables with setTimeouts:
var printOne = setTimeout(function() {
console.log("one!");
}, 500);
var printTwo = setTimeout(function() {
console.log("two!");
}, 50);
it's just for example. What I want is, to make a function(with async and await that will call the above variables, but in order. Like this:
theFunction(printOne, printTwo);
// Will output:
// one!
// two!
To accomplish that with async functions, you need to work along with promises.
An alternative is wrapping both setTimeout calls into a function which returns a promise:
var printOne = function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log("one!");
resolve();
}, 500);
})
}
var printTwo = function() {
return new Promise(function(resolve) {
setTimeout(function() {
console.log("two!");
resolve();
}, 50);
})
}
function theFunction(one, two) {
}
async function main() {
theFunction(await printOne(), await printTwo());
}
main();
Create a function that return promise which encapsulate setTimeout
var fnPromiseTimeout = async function(msg, time) {
return new Promise( (resolve) => setTimeout( () => {
//console.log(msg);
resolve(msg);
}, time ) );
};
Demo
var fnPromiseTimeout = async function(msg, time) {
return new Promise( (resolve) => setTimeout( () => {
//console.log(msg);
resolve(msg);
}, time ) );
};
async function f1(timer1, timer2)
{
console.log("start");
var a = await timer1;
console.log(a);
var b = await timer2;
console.log(b);
console.log("end");
}
f1(fnPromiseTimeout("one", 500), fnPromiseTimeout("two", 500));

Categories