5

How can I make my code run sequentially? For example,

  1. If I have a for loop which gets some data from a service, I want the n+1 iteration to run only after the nth iteration has completed.

  2. I want the code after the loop to execute only after the for loop has completed all interactions.

Example code:

someMethod() {

    for ( var i = 0; i < someLength; i++) {
        // get some data
        this.dataService.get(i).subscribe(data => {
            // do something with the data
        }); 
    }

    // 
    console.log ('print me only after all iterations');

    // ....
    // some more lines of code
}

Here is another example ( Plunker ) :

someMethod() {

    for ( var i = 0; i < 5; i++) {
        setTimeout(()=> {
            console.log('This is iteration' + i); 
        },500);
    }

    // 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
}

Any ideas?

8 Answers 8

9
+100

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();
Sign up to request clarification or add additional context in comments.

3 Comments

Plus 1 Nice answer. It might be worth mentioning toPromise
This does not work. console.log('print me only after all iterations'); is printed before the for loop has completed its iterations and also the iterations are not in order.
I've updated the example to be only console logs. The async and await are important. You can test this code at Typescript playground or even run it as is in Chrome (jsfiddle.net/xzrjds5n). The async / await keywords are important.
1

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

Comments

1

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

4 Comments

No I am not exactly looking for this. In any other programming language, C# for example, the code that comes after the loop will only execute once all the iterations have completed. I am looking for the same here. To run this line console.log('print me only after all iterations');, only after the for-loop has completely iterated
I think I see what you're saying.. how about this?
yes, something like that. I will test that further with more examples.
@Faisal if this helped guide you to your solution, could you mark it as the answer?
1

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

Comments

0

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).

Comments

0

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

Comments

-1

I think you need exact like this..
Just Run code snippets and see the result

async function someMethod() {
    for (var i = 0; i < 5; i++) {
        await new Promise(resolve => {
            setTimeout(()=> {
                console.log('This is iteration ' + i); 
                resolve();
            }, 1500);
        });
    }
    console.log ('print me only after all iterations');
}
someMethod();

1 Comment

This is copy of accepted answer. Why bother?
-2
SomeMethod(i, length){
       If(i< length){
          this.dataService.get(i).subscribe(  data => {
                 // do some business logic 
                 this.SomeMethod(i+1, length);

            }); 
       }else{
           console.log("Iteration completed");
       }}

Try this logical way

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.