Synchronisation problem using rxjs and old style callbacks - javascript

I have old-style library with 4 asynchronous functions - lets call them libA, libB, libC, libD (the running time of each is unknown/random) - when they finish they call my callback
I write loadString function which return observable (which should contains results of each callback function - I use string here for simplicity but it can be array of results) but it gives wrong result "AADDDDD". The expected result is "AADDDDDCCCCBBB". How to do it right using rxjs?
function loadString() {
let result = '';
return Observable.create(observer =>{
libA( n=> { result+='A'.repeat(n) });
libB( n=> { result+='B'.repeat(n) });
libC( n=> { result+='C'.repeat(n) });
libD( n=> {
result+='D'.repeat(n);
observer.next(result);
});
})
}
Below there is working snippet which you can copy to your answer and develop loadString function
// SET-UP
const { of, Observable } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
return Observable.create(observer =>{
libA( n=> { result+='A'.repeat(n) });
libB( n=> { result+='B'.repeat(n) });
libC( n=> { result+='C'.repeat(n) });
libD( n=> {
result+='D'.repeat(n);
observer.next(result);
});
})
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
UPDAE
I would like to not run lib functions in sequential way but parallel (they send some requests to API...)

A hacked together solution that illustrates your problem - you should only call observer.next after your last callback has been called. Just keep a running count. The below code isn't important, the knowledge of, "just wait until your last one gets called before emitting" is the key.
Here's the hacked together solution for the fun of it:
// SET-UP
const { of, Observable } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
const done = (observer,count) => val => {
result += val;
// THIS IF STATEMENT IS WHAT YOU WERE MISSING
if(!--count) return observer.next(result);
}
return Observable.create(observer =>{
const complete = done(observer,4);
libA( n=> complete('A'.repeat(n))),
libB( n=> complete('B'.repeat(n))),
libC( n=> complete('C'.repeat(n))),
libD( n=> complete('D'.repeat(n)));
})
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

Call each libX function from the callback of the previous one.
function loadString() {
let result = '';
return Observable.create(observer => {
libA(n => {
result += 'A'.repeat(n);
libB(n => {
result += 'B'.repeat(n);
libC(n => {
result += 'C'.repeat(n);
libD(n => {
result += 'D'.repeat(n);
observer.next(result);
});
});
});
})
});
}

libD is the ONLY thing that calls observer.next. As soon as that finishes, your observable will emit, even if the other ones haven't finished. So you need to wait. Try combineLatest (although that won't preserve order)?
// SET-UP
const { of, Observable, combineLatest } = rxjs;
const { map, switchMap, delay } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
// QUESTION: how to write below function body using rxjs?
function loadString() {
let result = '';
return combineLatest(
Observable.create(observer => libA(n => observer.next('A'.repeat(n)))),
Observable.create(observer => libB(n => observer.next('B'.repeat(n)))),
Observable.create(observer => libC(n => observer.next('C'.repeat(n)))),
Observable.create(observer => libD(n => observer.next('D'.repeat(n))))
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

We can also use bufferCount (technique from here )
// SET-UP
const { Subject } = rxjs;
const { take, bufferCount, map, finalize } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
function loadString() {
let result = new Subject();
libA( n=> { result.next('A'.repeat(n)); });
libB( n=> { result.next('B'.repeat(n)); });
libC( n=> { result.next('C'.repeat(n)); });
libD( n=> { result.next('D'.repeat(n)); });
return result.pipe(
bufferCount(4), // num of callbacks
take(1), // this will unsubscribe after 4 values received
map( r => r.join`` ),
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
}, e=>{}, ()=> console.log('final'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>
or less efficient scan (because it concat strings not once but everytime some task ends)
// SET-UP
const { Subject } = rxjs;
const { scan, take, last, map } = rxjs.operators;
// simulated lib function - not change this (the times are random)
function libA(callback) { setTimeout( _=>callback(2), 1000); }
function libB(callback) { setTimeout( _=>callback(3), 3000); }
function libC(callback) { setTimeout( _=>callback(4), 2000); }
function libD(callback) { setTimeout( _=>callback(5), 1500); }
function loadString() {
let result = new Subject();
libA( n=> { result.next('A'.repeat(n)); });
libB( n=> { result.next('B'.repeat(n)); });
libC( n=> { result.next('C'.repeat(n)); });
libD( n=> { result.next('D'.repeat(n)); });
return result.pipe(
take(4),
scan((acc, value) => acc + value),
last()
);
}
// TEST
let s = loadString().subscribe(str=> {
console.log(str); // wrong result: I expected "AADDDDDCCCCBBB" value
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.min.js" integrity="sha256-85uCh8dPb35sH3WK435rtYUKALbcvEQFC65eg+raeuc=" crossorigin="anonymous"></script>

Related

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);
});

Callbacks Exercise Javascript

I have been exercising callbacks and I got this exercise that I have been struggling with the syntax. Here is my code:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
doLaundry([wash, dry, fold]);
Invoking the doLaundry([wash,dry,fold]) is supposed to print out the following:
wash dry fold Done!
by calling this function (needs work)
function doLaundry() {
// Call functions
}
I tried this and it was close but the syntax is wrong or uneeded:
function doLaundry(actions, callback) {
actions.forEach((item, index) => {
wash(item, (error) => dry(item, (error) => fold(item, (error) => {})));
});
}
I'm really confused how to implement the doLaundry() with callback after checking out other simple tutorials. Any suggestions how to approach this?
Since the functions don't need to be asynchronous, I think you're making this a lot more complicated than it needs to be. Just iterate through the array of actions (functions) and call them. Then log Done at the end.
function wash() {
console.log('wash');
}
function dry() {
console.log('dry');
}
function fold() {
console.log('fold');
}
const doLaundry = (fns) => {
fns.forEach(fn => {
fn();
});
console.log('Done!');
}
doLaundry([wash, dry, fold]);
Or, if you must stick with the asynchronous functions, you can build up the callback chain starting from the last one in the chain and going backwards with reduceRight:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
const doLaundry = (fns) => {
const firstCallback = () => console.log('done');
const firstFn = fns.reduceRight(
(nextCallback, fn) => () => fn(nextCallback),
firstCallback
);
firstFn();
}
doLaundry([wash, dry, fold]);
Or, for an easier to understand approach, promisify each callback and await them:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
const toProm = fn => new Promise(resolve => fn(resolve));
const doLaundry = async (fns) => {
for (const fn of fns) {
await toProm(fn);
}
console.log('done');
}
doLaundry([wash, dry, fold]);
Try this simple code:
only one thing that you have to remember is, in the callback function if we are passed arguments, you have to write something in front of the callback like this
()=>
function wash(dry) {
console.log("wash");
setTimeout(dry, 3000);
}
function dry(fold) {
console.log("dry");
setTimeout(fold, 2000);
}
function fold(done) {
console.log("fold");
console.log("done");
}
setTimeout(() => wash(() => dry(() => fold("done"))), 4000);
function wash(callback){
setTimeout(()=>{
console.log('wash');
callback()
},3000)
}
function dry(callback){
setTimeout(()=>{
console.log('dry');
callback()
},2000)
}
function fold(callback){
setTimeout(()=>{
console.log('fold');
callback()
},1000)
}
function doLaundry(callback){
callback()
}
doLaundry(()=>{
wash(()=>{
dry(()=>{
fold(()=>{
console.log('done')
})
})
})
});
This one should do the job.
function doLaundry(actions) {
const [_wash, _dry, _fold] = actions
_wash(() => {
_dry(() => {
_fold(() => {
console.log('Done')
})
})
})
}
First line is destructuring the array, so it's elements are easier to access:
const [_wash, _dry, _fold] = actions
Function doLaundry takes array of callback functions as argument, which means when calling those functions inside of body of doLaundry, only names which it takes from arguments should be provided together with arguments that those callback functions are taking.
Since all of them take callbacks as arguments, arguments must be another function. First callback function's (in this case _wash) argument is another callback (_dry), therefore it takes another function as argument. If _wash's argument wasn't another function that takes callback as argument, it would be done like this:
_wash(_dry)
Last callback (_fold) also takes a callback as an argument which is in this case an anonymous function.

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>

Clear all kind of intervals

Imagine the scenario in which you have the main function which executes 2 functions which start intervals. These functions are imported as a NodeJS module and executed. Then in the main function after some time you clearIntervals. Also, note that there we'll be more intervals in the main function in the future.
So the main function is
(() => {
const intervals = [];
intervals.push(require('./simpleInterval')());
intervals.push(require('./asyncInterval')());
setTimeout(() => {
intervals.forEach(id => clearInterval(id));
}, 1200)
})();
One of these methods is simply
const intervalFoo = () => {
return setInterval(() => {
console.log('interval simple')
}, 500);
};
module.exports = intervalFoo;
but the second one contains some asynchronous code which can perform longer than interval gap but I don't want it to start before the previous "iteration" didn't finish. The solution in this kinda situation is to clear interval by id at the beginning and then reassign it at the end (but within the body) of interval. So the code of asyncInterval.js is:
const sleep = require('./utilities/sleep');
const intervalFoo = () => {
let intervalId;
const checkE2Interval = async() => {
clearInterval(intervalId);
console.log('interval async');
await sleep(120); //some long action
return intervalId = setInterval(checkE2Interval, 100);
};
return intervalId = setInterval(checkE2Interval, 100); //returning id
};
module.exports = intervalFoo;
(sleep is just a promise which resolves after timeout time given as argument)
The issue about this is that I'm returning intervalId from asyncInterval.js also in the interval and my problem is that I don't know how am I suppose to clear this thing.
Provide cancellation functions rather than providing raw handles, and pass your function an object with a flag it can check for whether it's been cancelled:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
Since 0 is an invalid timer ID, we can safely use it as a flag that the interval has been cancelled. Note that there is a slight difference between chained setTimeout (above) and setInterval (setInterval's handling of the delay between intervals is...interesting.) Also note that nothing above prevents the function being called while it's paused on sleep. To do that, you'd have to have a guard and to have the function specifically support async functions:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
Use that function instead of setInterval.
In your async function, if it never has reason to stop itself:
const intervalFoo = () => {
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
};
return mySetInterval(checkE2Interval, 100); //returning id
};
If it does have reason to stop itself, save cancel:
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
Then, where you need to cancel:
(() => {
const cancellers = [];
cancellers.push(require('./simpleInterval')());
cancellers.push(require('./asyncInterval')());
setTimeout(() => {
cancellers.forEach(cancel => cancel());
}, 1200)
})();
Live Example:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
Live Example with the running flag:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
console.log('awake');
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
You can generalize this further, but you get the basic idea.

Wait for a functions to finish in sequence 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>

Categories