Most hight-level programming languages ships with iteration statements, dart is not an exception.
For one to handle highly scalable and efficient business logic using dart, a detailed knowledge of asynchronous operations, futures, loops among others is a can’t-do-without.
In this article, We’ll focus specifically on the
for..in
andforEach
loops as used in asynchronous operations.
Generally, both the for-in
and forEach
constructs are used to loop over iterables(List, Set, etc). Both have a return type of void. .i.e(a new value can not be returned from these methods), neither do they expose the current index of the iteration unlike the typical for..loop
.
Enough of the general notes, let’s see how these constructs handle asynchronous operations in dart.
Take a closer look at the examples below:
List<Person> persons = [
Person(
name: "Emeruche U.K",
images:["ImageProfile", "My Image2"],
),
];
class Person{
String name;
List<String> images;
Person({this.name, this.images});
}
void main() {
Future uploadImages({images, name})async{
return ["Image 1", "image 2"];
}
Future updateProfile(Person person) async{
List<String> newImageUrls = [];
person.images.forEach((image) async{
if (image.runtimeType == String) {
dynamic url = await uploadImages(images: [image], name: person.name);
print("forEach URL: $url");
newImageUrls.addAll(url);
} else {
newImageUrls.add(image);
}
});
print("Profile Images f1: $newImageUrls");
person..images = newImageUrls;
}
updateProfile(persons[0]);
}
From the above snippet, using the for..Each
construct might seem like a natural choice when looping over a list using async/await. Typically, we expect the synchronous-reading magic of async/await
to do what it says and actually await
the promise. Often times this gives an unexpected output or even throw a ReferenceError
if the result of the operation is being used somewhere else in the application (as seen in above code).
To fix this, we can either switch to the for..in
construct or use the Future.forEach
method. This should do the trick
Future updateProfile2(Person person) async {
List<String> newImageUrls = [];
for (var image in person.images) {
if (image.runtimeType == String) {
dynamic url = await uploadImages(images: [image], name: person.name);
print("for..in URL: $url");
newImageUrls.addAll(url);
} else {
newImageUrls.add(image);
}
}
print("Profile Images f2: ${newImageUrls}");
person..images = newImageUrls;
}
First, we changed the for..Each block to a for..in construct…why? Switching to a for..in block solved the problem because the for..each
returns the empty result set
first before processing the await function inside the forEach. It just applies the function on each element and calls next without awaiting for the asynchronous operation to return. But the for..in construct on the other hand, actually awaits the result of the execution of the function before calling next
Future updateProfile3(Person person) async {
List<String> newImageUrls = [];
await Future.forEach(person.images, (image)async{
if (image.runtimeType == String) {
dynamic url = await uploadImages(images: [image], name: person.name);
print("Future.forEach URL: $url");
newImageUrls.addAll(url);
} else {
newImageUrls.add(image);
}
});
print("Profile Images f3: $newImageUrls");
person..images = newImageUrls;
}
The Future.forEach()
waits for each Future to be completed before moving to the next element.
When you need to wait for multiple Futures to complete irrespective of their order, you can use Future.wait() method like this:
Future.wait(person.images.map(functionCall));
or
Future.wait([futureOne(), futureTwo(), …]).then((res) => functionToCallAfterResult(res));
Error handling in asynchronous code
Errors from your asynchronous code can be handled using the try..catch
block in dart. Essentially, if an error is thrown within the try block, such can be received and handled with the catch block.
Top comments (1)
Thank's very much helpful