Reputation: 466
Thanks for viewing my question. I am hopeful that you might help me go in the right direction.
Problem: User sends a list of company name and server sends the corresponding logo back. The restriction is that the logo needs to be placed left to right and then top to bottom. The order should not change.
Approach Followed: We are using an Array of Company Names appearing row wise - Like: [ [Companies_Row1] , [Companies_Row2], [Companies_Row3] ]
Each [Companies_Row] has values like [‘Ford’, ‘BMW’, ‘Audi']
[
We expect the logos to appear in order, however presently we are getting them in random order.
Solution we are thinking is to iterate over the arrays and make use of Promises. However we are struggling to implement this since last two days. Please help us resolve the same.
Code Snippets:
// arrayOfCompanyNames - contains an Array of [Array of Company Names] appearing in a row. Please Refer Screenshot.
// Function where we are traversing the company Name and making call
function getCompanyLogos(arrayOfCompanyNames) {
var promise = new Promise(function(resolve, reject) {
resolve(1);
});
promise.then(function(){
arrayOfCompanyNames.forEach(function(item) {
item.forEach(function(value, index) {
if(index == item.length - 1){
// When a row is complete then move to the next row.
promise = promise.then(LogoFetchPromis(value, true));
} else {
promise = promise.then(LogoFetchPromis(value));
}
});
});
});
}
function LogoFetchPromis(carName, wrapNow){
return new Promise(function(resolve, reject) {
$.ajax({
url: "/getLogo/" + carName,
dataType: 'text'
})
.done(function(response) {
resolve(response);
// logos is the section where logos should appear
$('.logos').append(response);
if (wrapNow)
$('.logos').append('<br>');
})
.fail(function(response) {
reject(Error(response));
});
});
}
Please help us find a resolution for the same.
Upvotes: 0
Views: 326
Reputation: 13682
Keep it simple. One solution is first fetch all of your images by building an array of promises reproducing the structure of arrayOfCompanyNames
then use Promise.all()
to keep the order of the promises result. And then you can loop over the results array and show the logos (add error management as you need).
// arrayOfCompanyNames - contains an Array of [Array of Company Names] appearing in a row. Please Refer Screenshot.
var arrayOfCompanyNames;
// Function where we are traversing the company Name and making call
function getCompanyLogos(arrayOfCompanyNames) {
// build an array of promises mirroring arrayOfCompanyNames
var promises = [];
arrayOfCompanyNames.forEach(function (subArray) {
var subPromises = [];
subArray.forEach(function (carName) {
// $.ajax is a promise so you use it directly
subPromises.push($.ajax({
url: '/getLogo/' + carName,
dataType: 'text'
}));
});
promises.push(Promise.all(subPromises));
});
// show everything, results is nicely formatted so you know when to <br>
return Promise.all(promises).then(function done(results) {
// results look like [[row1], [row2], [row3]]
results.forEach(function (row) {
row.forEach(function (carLogo) {
$('.logos').append(carLogo);
});
$('.logos').append('<br>');
});
})
}
The Promise.all()
solution will introduce a delay, the logos will show at once when they're all fetched. They will be downloaded all at the same time so be careful if it's not your server you're requesting (almost 100 concurrent requests is consequent).
The other way is what you started, building a promise chain.
// arrayOfCompanyNames - contains an Array of [Array of Company Names] appearing in a row. Please Refer Screenshot.
var arrayOfCompanyNames;
// Function where we are traversing the company Name and making call
function getCompanyLogos(arrayOfCompanyNames) {
// this is enough to create a 'base' resolved promise
var promise = Promise.resolve();
arrayOfCompanyNames.forEach(function (item) {
item.forEach(function (value, index) {
if (index == item.length - 1) {
// When a row is complete then move to the next row.
promise = promise.then(LogoFetchPromis.bind(null, value, true));
} else {
promise = promise.then(LogoFetchPromis.bind(null, value));
}
});
});
return promise;
}
function LogoFetchPromis(carName, wrapNow) {
// don't create a new Promise here, $.ajax is already a promise
return $.ajax({
url: "/getLogo/" + carName,
dataType: 'text'
}).done(function (response) {
// logos is the section where logos should appear
$('.logos').append(response);
if (wrapNow)
$('.logos').append('<br>');
}).fail(function (response) {
// manage error here is needed
});
}
I commented the changes but the most important is promise.then(LogoFetchPromis(value));
. You're calling LogoFetchPromis()
directly, that's why your logos show randomly, all the $.ajax are actually done at once. In the fixed code (promise.then(LogoFetchPromis.bind(null, value)
), bind() returns a Function that is not executed until promise
is resolved so LogoFetchPromis()
will be called one at a time and your logos should be displayed in order.
Upvotes: 1