I have some angular code that calls two separate backend services via $http.get. The backend is ASP.NET MVC 5.
I call the services via $http.get, and since I need a response from both services before continuing, I wrap the returned promises in $q.all. However, there seems be a massive overhead when resolving the promises via $q.all compared to resolving the promises sequentially (i.e. call the second service in the .then callback of the first promise).
The overhead appears in the TTFB (Time to first byte).
I can't figure out why $q.all would be slower than sequentially waiting for one promise to resolve before starting the next. In fact, I thought $q.all would be faster since it would allow me to start the second service call before the first has resolved.
Read on for implementation details.
These backend services are fairly lightweight:
ProductsController:
[HttpGet]
public Dictionary<string, PriceListTypeDto> GetPriceListTypesForProducts([FromUri] List<string> productErpIds)
{
// Work to get PriceListTypes. Work takes 40 ms on avg.
}
UserController:
[HttpGet]
public int? GetUserOrganizationId()
{
// work to get orgId. 1-10 ms runtime on avg.
}
Javascript functions that call these services:
var addPriceListTypes = function (replacementInfoObjects, productErpIds) {
return productService.getPriceListTypesForProducts(productErpIds) // Returns promise from $http.get
.then(function (response) {
// Simple work, takes 1 ms.
})
.catch(function () {
});
}
var addOrganizationSpecificDetails = function (replacementInfoObjects) {
return userContextService.getUserOrganizationId() // Returns promise from $http.get
.then(function (response) {
// Simple work, takes 1 ms.
})
.catch(function () {
});
};
Handling the promises:
Option 1: Takes ~600 ms before $q.all.then is called.
mapping-service.js:
var deferredResult = $q.defer();
var orgDetailsPromise = addOrganizationSpecificDetails(productInfoObjects);
var priceListPromise = addPriceListTypes(products, productErpIds);
$q.all([orgDetailsPromise, priceListPromise])
.then(function () {
deferredResult.resolve(productInfoObjects);
}).catch(function () {
deferredResult.reject();
});
return deferredResult.promise;
Performance via Chrome devtools:
Option 2: Takes ~250 ms before both promises are resolved:
mapping-service.js:
var deferredResult = $q.defer();
addOrganizationSpecificDetails(productInfoObjects)
.then(function () {
addPriceListTypes(productInfoObjects, productErpIds)
.then(function () {
deferredResult.resolve(productInfoObjects);
})
.catch(function () {
deferredResult.reject();
});
})
.catch(function () {
deferredResult.reject();
});
return deferredResult.promise;
Performance via Chrome devtools:
Where does the overhead in option 1 come from? What have I missed? I'm completely stumped here. Please let me know if you need more information.