Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to guarantee sequential order with angular http rest api in for loop?

I'm trying to create a form that allows you to create multiple resources in sequential order.

Example below

Floor 1
Floor 2
Floor 3
...
Floor 9

The problem with the code is that the order is not guarantee.

My code below

let startAt = this.addAreasForm.controls['startAt'].value
const name = this.addAreasForm.controls['name'].value
const newArea = {name: name}

for (let i = 1; i < (amount + 1); i++) {
  newArea.name = name + ' ' + startAt
  startAt++
  this.areasService.createArea(newArea, parentId)
    .subscribe(
      area => this.added.emit(area)
    )
}

Can come back like

Floor 2
Floor 3
Floor 1
Floor 5
Floor 4

How do you handle async api calls to guarantee sequential order?

like image 254
locnguyen Avatar asked Aug 17 '17 14:08

locnguyen


2 Answers

You can use async / await for that purpose with the Promise resolve:

for (let i = 1; i < (amount + 1); i++) {
    await new Promise(resolve => {
        newArea.name = name + ' ' + startAt
        startAt++
        this.areasService.createArea(newArea, parentId)
            .subscribe(
                area => { 
                    this.added.emit(area);
                    resolve();
                });
        });
}

Remember to put async before your function. See this demo on StackBlitz.

like image 154
Faisal Avatar answered Nov 05 '22 19:11

Faisal


You can try something like this, I don't exactly all your code from your services, but the main idea is this: In order to execute async code in order, you can build an array of promises and then to use Promise.all to take each result in the same order from the creation: Promise.all

let startAt = this.addAreasForm.controls['startAt'].value;
const name = this.addAreasForm.controls['name'].value;
const newArea = {name: name};

Keep your services into variables I don't know from where your context comes.

 const areasService = this.areasService,
    added = this.added;

Make a function that create a promise for your subscribe:

function createAreaPromise(newArea, parentId) {
    return new Promise((resolve, reject) => {
        areasService.createArea(newArea, parentId)
            .subscribe(area => resolve(area));
    });
}

Than another function to build multiple an array of promises:

function buildPromises() {
    let promises = [];

    for (let i = 1; i < (amount + 1); i++) {
      newArea.name = name + ' ' + startAt
      startAt++
      promises.push(createAreaPromise(newArea, parentId));
    }

    return promises;
}

Then solve them with Promise.all, to obtain the same order from creation

let promises = buildPromises();
Promise.all(promises)
    .then(results => {
        results.forEach(result => added.emit(result));
    });

Here a live example:

function random() {
	return Math.floor(Math.random() * 5);
}

function makePromise(index) {
	return new Promise((resolve) => {
		setTimeout(() => {
			resolve(index);
		}, random() * 1000);
	});
}

function buildPromises() {
	let promises = [];
	for(let i = 0; i < 5; i++) {
		promises.push(makePromise(i));
	}

	return promises;
}

let promises = buildPromises();
Promise.all(promises)
	.then(results => {
		results.forEach(result => {
			console.log(result);
		});
	});
like image 1
Alexandru Buturuga Avatar answered Nov 05 '22 17:11

Alexandru Buturuga