How can I make my code run sequentially? For example,
If I have a for loop which gets some data from a service, I want the n+1
iteration to run
You could wrap each iteration in a Promise and await it:
async function someMethod() {
for (var i = 0; i < 5; i++) {
await new Promise(resolve => {
setTimeout(()=> {
console.log('This is iteration ' + i);
resolve();
}, 500);
});
}
console.log ('print me only after all iterations');
}
someMethod();
You can do it with Promise.
someMethod() : Promise<any> {
return new Promise((resolve) => {
for ( var i = 0; i < someLength; i++) {
// get some data
this.dataService.get(i).subscribe(data => {
// do something with the data
});
if(i==someLength-1){resolve();}
}
}).then(()=>{
//
console.log ('print me only after all iterations');
// ....
// some more lines of code
})
}
Are you looking for something like this? (plunker)
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`;
this.someMethod();
}
doTimeout(currentIndex:int){
return new Promise(resolve => {
setTimeout(()=> {
console.log("This is iteration " + currentIndex);
resolve();
},500);
});
}
async someMethod() {
for(let i=0;i<5;i++){
await this.doTimeout(i);
}
// I want to execute this line of code only after the
// for loop has completed all iterations.
console.log ('print me only after all iterations');
// ....
// some more lines of code
}
}
Sources: What is the JavaScipt Version of sleep? and Combination of async function + await + setTimeout
I suggest adapting it to use the zip
"combining operator" from rxjs:
http://reactivex.io/documentation/operators/zip.html
EDIT: here is an example: https://www.learnrxjs.io/operators/combination/zip.html
Although in your case you would have to pass it as an array probably ( zipArray
).
As Javascript is a single thread language, it is hard to do what exactly you want to achieve unless you use Promise or other callback architecture
.
There are many ways to achieve it through PROMISEs
. Here, I'll show you how can you achieve the same using advance JavaScript concept called Async & Await
in Angular framework.
Please note there are many ways with Promise but my intention is to introduce you to new async & await
concept where you don't need to chain the callback for success and reject methods.
DEMO : https://plnkr.co/edit/16k66yRjXLPwTM50kYNS
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`;
this.someMethod();
}
const someMethod_Promise = () => {
return new Promise((resolve,reject)=>{
for ( var i = 0; i < 5; i++) {
console.log('printing value of i ' + i);
if(i==4) // real condition
resolve(true);
}
})
}
const someMethod = async()=>{
let result= await this.someMethod_Promise();
if(result){
console.log ('print me only after all iterations');
}
}
}
Promise based solution:
Promise.all() takes an array of promises and fires them all at the same time. Then once all of the promises resolve it will run the callback.
let dataService = {
get: function(i) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 100, i);
});
}
}
let promises = [];
for (var i = 0; i < 3; i++) {
// get some data
promises.push(dataService.get(i));
}
Promise.all(promises).then(values => {
console.log ('print me only after all iterations');
console.log(values);
});
Working sample: http://jsbin.com/ruqiwoxono/edit?js,console
Promise.all docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Rxjs based solution:
forkJoin basically does the same thing as Promise.all() but for observables
let dataService = {
get: function(i) {
return Rx.Observable.of(i);
}
}
let observables = [];
for (var i = 0; i < 3; i++) {
// get some data
observables.push(dataService.get(i));
}
const example = Rx.Observable.forkJoin(observables);
const subscribe = example.subscribe(values => {
console.log ('print me only after all iterations');
console.log(values);
});
Working sample: http://jsbin.com/jolotuyoxa/edit?js,console
Rxjs forkjoin docs: https://www.learnrxjs.io/operators/combination/forkjoin.html