How to call javascript array of methods having callbacks to run sequentially? - javascript

I have the following methods to be called sequentially.
Note that timeout is differing so by default it will run based on timeout.
function asyncTask1(done) {
setTimeout(() => {
console.log('task 1 done');
done(1);
}, 500);
}
function asyncTask2(done) {
setTimeout(() => {
console.log('task 2 done');
done(2);
}, 400);
}
function asyncTask3(done) {
setTimeout(() => {
console.log('task 3 done');
done(3);
}, 300);
}
function sequential(tasks = []) {
}
sequential(tasks);

You can do it recursively:
function sequential([first, ...last], done) {
if (!first) done();
else first(() => sequential(last, done);
}

This was a very useful reply, but took me a bit of time to put it all together. Here is the function in use
function done() {
console.log("DONE")
}
var callbacks = [
function callback1(next) {
console.log("callback1")
next()
},
function callback2(next) {
console.log("callback2")
next()
},
function callback3(next) {
console.log("callback3")
next()
},
function callback4(next) {
console.log("callback4")
next()
},
function callback5(next) {
console.log("callback5")
next()
}
]
function sequential([first, ...last], done) {
if (!first)
done();
else
first(() => {sequential(last,done);})
}
//And call it.
sequential(callbacks, done);

Related

I want print the functions one by one in an order like function1 , function2 and function3 so I used call back

function display1(res) {
setTimeout(() => {
console.log('1st message')
res();
}, 5000)
}
function display2() {
setTimeout(() => {
console.log('2nd message')
res1();
}, 2000)
}
function display3() {
console.log('3rd message');
}
display1(display2);
display3();
Output :
3rd message
1st message
2nd message
I am getting this as my output, kindly help me to print 1st message, 2nd message and 3rs message, in this order.
function display1(cb) {
setTimeout(() => {
console.log('1st message');
cb();
}, 5000);
}
function display2(cb) {
setTimeout(() => {
console.log('2nd message');
cb();
}, 2000);
}
function display3() {
console.log('3rd message');
}
display1(display2.bind(null, display3));
Will do what you want.
You need to properly take and action the callback in display2, and then you also need to use the bind function, in order to pass the callback (cb) as an argument to display2, whilst it's already being called as an argument to display1.
If you don't use bind, display1 and display2 will both execute immediately, which will not give the correct result.
Look in to promises, as that's a much easier way to handle asynchronous code.
One easy fix would be:
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function display1(res) {
await timeout(1000);
console.log("1")
}
async function display2() {
await timeout(2000);
console.log("2")
}
function display3() {
console.log("3")
}
display1().then(() => display2()).then(() => display3());
use This Way
Promise.resolve('foo')
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('strfdfding');
console.log('first');
}, 2000);
});
})
.then(function(string) {
return new Promise(function(resolve, reject){
setTimeout(function() {
resolve('string');
console.log('second');
}, 1000)
});
})
.then(function(string) {
return new Promise(function(resolve, reject){
setTimeout(function() {
resolve('string');
console.log('third');
}, 1)
});
});
Click here to read more About Promise

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.

Synchronisation problem using rxjs and old style callbacks

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>

JavaScript - replace setTimeout with async / await

First, I know this is a common question. I'm trying to get a handle on how to use async / await in place of setTimeouts, but all the examples I see online use a setTimeout to simulate the async. This throws me off when it's a set timeout that I'm trying to replace.
In the function below, I want this.filteredResultsto await the results of an API call before trying to filter those results and assign it to this.filteredResults.
getResults() {
let allResults= airtableQuery.getTable("Transfers"); // API call using imported 'getTable' function
console.log(allResults); // returns full array ▶[] although it's not available for filtering yet.
setTimeout(() => { // I want to replace this timeout
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
}, 250); // random ms that is roughly how long airtableQuery takes for the API call.
},
And the airtableQuery:
getTable(table) {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
}
}
);
return recordsArr;
},
Please make the outer function an async function and then await the results before filtering them.
async function getResults() {
let allResults = await airtableQuery.getTable("Transfers");
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
},
Given that getTable() is not a Promise, await will not do anything. For that reason, we can make getTable() return a Promise which will resolve with recordsArr.
getTable(table) {
return new Promise((resolve, reject) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
reject(err)
}else {
resolve(recordsArr)
}
}
);
})
}
Hope it helps.
i always likes primise,this my code show you
getTable(table) {
return new Promise((res, rej) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
res(recordsArr)
},
function done(err) {
if (err) {
this.$toasted.error(err);
rej(err)
}
}
);
})
}
getResults() {
airtableQuery.getTable("Transfers").then(res => {
let allResults = res
console.log(allResults);
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
});
}

can I use async.waterfall inside async.parallel?

I want to call two functions and get the results in parallel but one of the function's results needed to be adapted. So the function structure is:
function test(cb) {
async.parallel({
func1: function foo(cb1) {
cb(null, {});
},
func2: function bar(cb2) {
async.waterfall([
function adapt1(next) {
//do something;
},
function adapt2(next) {
//do something;
}
], function handler(err, res) {
//do something.
})
}
}, function handler2(err, res) {
cb(null, {});
})
}
However, it just seems hang there forever. not sure if I can use async in this way....
Sure you can! You have to be sure to call your callbacks in the correct order and in the first place. For example, func1 should be calling cb1 not cb. Secondly, your waterfall is not invoking their callbacks at all.
Take this code for example.
'use strict';
let async = require('async');
function test(callback) {
async.parallel({
func1: function(cb) {
cb(null, { foo: 'bar' });
},
func2: function(cb) {
async.waterfall([
function(cb2) {
cb2(null, 'a');
},
function(prev, cb2) {
cb2(null, 'b');
}
], function(err, result) {
cb(err, result);
});
}
}, function(err, results) {
callback(err, results);
});
}
test(function(err, result) {
console.log('callback:', err, result);
});
Outputs: callback: null { func1: { foo: 'bar' }, func2: 'b' }

Categories