Asynchronous API calls taking 2x or 3x longer than synchronous API calls?

I am trying to load a lot of objects into a tableview. Naturally, I used pageSize and offset to load all of the data in chunks, so as to make it seem more bearable to the user. I am making the API calls asynchronously and recursively calling the method that queries for the data, but it is taking a VERY long time. When I try the same query synchronously, it is 2 or 3 times faster, but I am unable to reload the table view in the recursive call that loads the data. My question is two fold:

  1. Why do the asynchronous calls take so much longer (is that normal)?
  2. What is the best way to load a lot of data into a table view (or collection view) using pageSize and offset (and not taking forever!)?
    Thank you for your support, it will be very much appreciated.

Hi Cooper,

The first advice I can give you is to set pageSize to its max value, which is 100, if you don’t do it yet. Though in case you have really many objects it the table you will still have to call the method several times.
Also instead of using offset you may try to use BackendlessCollection’s nextPage() method, which will load the next pageSize results.

We would be thankful if you could provide some measurements with a sample code, which would prove that asynchronous requests really take much longer. The sample code would also help us to reproduce the behaviour and possibly make an improvement based on it.

Won’t setting the pageSize to 100 significantly increase the time it takes for the query to return the data? I don’t want it to take long to present the data to the user, which is why I am using paging in the first place as opposed to loading all of the data right away. For instance, in messaging, I fear that setting the pageSize to 100 (rather than something like 15 or 20) would cause the user to have to wait very long before seeing anything.

Some measurements: I asynchronously queried for 3 data objects - it took on average 2.3 seconds to return the data (there are many properties, which I’m sure contributes). Synchronously, it took on average .75 seconds. This huge difference surprised me, which is why I asked a question here, and caused me to think that this kind of behavior isn’t normal.

Thank you for your suggestion of using nextPage(), that sounds like a very good idea, but I am unsure of how to implement it in my method. I read the docs but can’t seem to get it to work.

My method is as follows:

-(void)loadEvents
{
BackendlessDataQuery *dataQuery = [BackendlessDataQuery query];
dataQuery.whereClause = [NSString stringWithFormat:@"category.objectId = '%@'", categoryToDisplay.objectId];
QueryOptions *queryOptions = [QueryOptions query];
queryOptions.related = [NSMutableArray arrayWithArray:@[@"host", @"rsvpdUsers", @"photos", @"comments", @"ratings", @"location", @"category"]];
int pageSize = 2;
queryOptions.pageSize = @(pageSize);
dataQuery.queryOptions = queryOptions;
[backendless.persistenceService find:[Event class] dataQuery:dataQuery response:^(BackendlessCollection *eventsCollection)
{
[events addObjectsFromArray:eventsCollection.data];
[self.tableView reloadData];
}
error:^(Fault *fault)
{
NSLog(@"Fault: %@", fault);
}];
}

Where do I put the nextPage() call? I assume under my reloading the tableview’s data, but how do I do it?

I look forward to hearing from you about this odd behavior and I appreciate your response.

Could you please provide the samples you use to measure the execution time of sync and async methods, so that we ca reproduce that?

Here is the asynchronous API call:

-(void)loadEvents{
BackendlessDataQuery *dataQuery = [BackendlessDataQuery query];
dataQuery.whereClause = [NSString stringWithFormat:@"category.objectId = '%@'", categoryToDisplay.objectId];
QueryOptions *queryOptions = [QueryOptions query];
queryOptions.related = [NSMutableArray arrayWithArray:@[@"host", @"rsvpdUsers", @"photos", @"comments", @"ratings", @"location", @"category"]];
int pageSize = 2;
queryOptions.pageSize = @(pageSize);
dataQuery.queryOptions = queryOptions;
[backendless.persistenceService find:[Event class] dataQuery:dataQuery response:^(BackendlessCollection *eventsCollection)
{
[events addObjectsFromArray:eventsCollection.data];
[self.tableView reloadData];
}
error:^(Fault *fault)
{
NSLog(@"Fault: %@", fault);
}];
}

Here is the synchronous API call:

-(void)loadEventsWithRunsThroughQuery: (int)numberOfRuns{
NSLog(@"Start load #%i", numberOfRuns);
BackendlessDataQuery *dataQuery = [BackendlessDataQuery query];
dataQuery.whereClause = [NSString stringWithFormat:@"category.objectId = '%@'", categoryToDisplay.objectId];
QueryOptions *queryOptions = [QueryOptions query];
queryOptions.related = [NSMutableArray arrayWithArray:@[@"host", @"rsvpdUsers", @"photos", @"comments", @"ratings", @"location", @"category"]];
int pageSize = 2;
queryOptions.pageSize = @(pageSize);
queryOptions.offset = @(numberOfRuns * pageSize);
dataQuery.queryOptions = queryOptions;
Fault *error = nil;
BackendlessCollection *collection = [backendless.persistenceService find:[Event class] dataQuery:dataQuery error:&error];
if (collection.data.count <= pageSize)
{
[events addObjectsFromArray:collection.data];
[self.tableView reloadData];
NSLog(@"End load #%i", numberOfRuns);
if (collection.data.count == pageSize)
{
[self loadEventsWithRunsThroughQuery:numberOfRuns + 1];
}
}
else if (collection.data.count > pageSize)
{
NSLog(@"VERY BAD - COLLECTION.DATA HAS MORE THAN %i (pageSize) OBJECT", pageSize);
}
}

Please also respond to my question about how to integrate the “nextPage()” method. Thank you.

About using of nextPage() method you could investigate this our sample project (it contains obj-c and swift targets). You can try it with our appId and secretKey - or set yours and uncomment a line in viewDidLoad():

addRestaurants()