Async/Await/then in Dart/Flutter - flutter

I have a flutter application where I am using the SQFLITE plugin to fetch data from SQLite DB. Here I am facing a weird problem. As per my understanding, we use either async/await or then() function for async programming.
Here I have a db.query() method which is conducting some SQL queries to fetch data from the DB. After this function fetches the data, we do some further processing in the .then() function. However, in this approach, I was facing some issues. From where I am calling this getExpensesByFundId(int fundId)function, it doesn't seem to fetch the data properly. It's supposed to return Future> object which will be then converted to List when the data is available. But when I call it doesn't work.
However, I just did some experimentation with it and added "await" keyword in front of the db.query() function and somehow it just started to work fine. Can you explain why adding the await keyword is solving this issue? I thought when using .then() function, we don't need to use the await keyword.
Here are my codes:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
// The await in the below line is what I'm talking about
await db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
return expenseList;
}

In simple words:
await is meant to interrupt the process flow until the async method has finished.
then however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async method is finished.
In your example, you cannot achieve what you want when you use then because the code is not 'waiting' and the return statement is processed and thus returns an empty list.
When you add the await, you explicitly say: 'don't go further until my Future method is completed (namely the then part).
You could write your code as follows to achieve the same result using only await:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
List<Map<String,dynamic>> expList = await db.query(expTable,where: '$expTable.$expFundId = $fundId');
expList.forEach((Map<String, dynamic> expMap) {
expenseList.add(Expense.fromMap(expMap));
});
return expenseList;
}
You could also choose to use only the then part, but you need to ensure that you call getExpensesByFundId properly afterwards:
Future<List<Expense>> getExpensesByFundId(int fundId) async {
Database db = await database;
List<Expense> expenseList = List();
return db.query(expTable,where: '$expTable.$expFundId = $fundId')
.then((List<Map<String,dynamic>> expList){
expList.forEach((Map<String, dynamic> expMap){
expenseList.add(Expense.fromMap(expMap));
});
});
}
// call either with an await
List<Expense> list = await getExpensesByFundId(1);
// or with a then (knowing that this will not interrupt the process flow and process the next instruction
getExpensesByFundId(1).then((List<Expense> l) { /*...*/ });

Adding to the above answers.
Flutter Application is said to be a step by step execution of code, but it's not like that.
There are a lot of events going to be triggered in the lifecycle of applications like Click Event, Timers, and all. There must be some code that should be running in the background thread.
How background work execute:
So there are two Queues
Microtask Queue
Event Queue
Microtask Queue runs the code which not supposed to be run by any event(click, timer, etc). It can contain both sync and async work.
Event Queue runs when any external click event occurs in the application like Click event, then that block execution done inside the event loop.
The below diagram will explain in detail how execution will proceed.
Note: At any given point of application development Microtask queue will run then only Event Queue will be able to run.

When making class use async for using await its simple logic to make a wait state in your function until your data is retrieve to show.
Example: 1) Its like when you follow click button 2) Data first store in database than Future function use to retrieve data 3) Move that data into variable and than show in screen 4) Variable show like increment in your following/profile.
And then is use one by one step of code, store data in variable and then move to next.
Example: If I click in follow button until data store in variable it continuously retrieve some data to store and not allow next function to run, and if one task is complete than move to another.
Same as your question i was also doing experiment in social media flutter app and this is my understanding. I hope this would help.

A Flutter question from an answer from your answer.
await is meant to interrupt the process flow until the async method has finished. then however does not interrupt the process flow but enables you to run code when the async method is finished. So, I am asking diff. between top down & bottom down process in programming.

Related

Vue3, firestore, useFirestore: How to get notified when binding is ready?

I'm currently migrating my project from Vue2+Vuex to Vue3+pinia. The storage of choice is still firebase. To keep my local storage in sync with the remote firebase-database I want to setup a (one-way) binding. I plan to use useFirestore as documented here.
I wrapped in a pinia action:
async bindTodos () {
this.todos = todos = useFirestore(collection(db, 'todos'));
}
with this.todos being defined in pinias state.
How can I maintain a boolean in the pinia state (i.e. todosReady) that get's updated when the todos were received the first time. Vuex/bindFirestoreRef used to return a promise. Or I am supposed to use import {watch} from "vue" and simply watch for changes in the returned Ref? Hope I'm on the right track!

Swift async/await in for loop

I am scratching my head on new async/await pattern in Swift 5.5 announced in WWDC 2021 and there seems to be lot of learning involved and not as easy to grasp as is pretended to be. I just saw this for loop for instance in WWDC video:
for await id in staticImageIDsURL.lines {
let thumbnail = await fetchThumbnail(for: id)
collage.add(thumbnail)
}
let result = await collage.draw()
As I understand, every iteration of for loop will suspend the for loop till fetchThumbnail() finishes running (probably on a different thread). My questions:
What is the objective of await id in the for loop line? What if we have the for loop written as following without await?
for id in staticImageIDsURL.lines {
}
Does the for loop above always ensures that images are added to collage in sequential manner and not in random order depending on which thumbnails are fetched early? Because in classic completion handler way of writing code, ensuring sequential order in array requires some more logic to the code.
The await id means geting an id element from the staticImageIDsURL.lines is an asynchronous operation in itself.
for await id in staticImageIDsURL.lines
This operation has to complete before we enter for loop's body for that iteration. You should read AsyncSequence docs to know more on this OR can watch Meet AsyncSequence WWDC 2021 session.
For each iteration, you are waiting for current operation to complete when you say this.
let thumbnail = await fetchThumbnail(for: id)
This line will suspend the function each time a new fetch call is initiated, so these thumbnails calls are guaranteed to be completed sequentially. These calls NEVER happen in parallel, first has to complete before second one is initiated.

Should I await expect(<async>) conditions

https://www.protractortest.org/#/async-await shows an example of using async/ await in protractor, but includes the line:
expect(await greeting.getText()).toEqual('Hello Julie!');
But I don't understand how that can be correct: if the greeting.getText() is async (indicated by the await), then the text won't be known until after that line has completed. Isn't:
await expect(await greeting.getText()).toEqual('Hello Julie!');
So we definitely wait for the text to be obtained (and checked) before we move on. In this example, it's not too important (assuming the expect check does execute), but in general, is there any risk of re-ordering the getText() with further operations (which may remove it from the DOM, for example).
Is it in practice safe if it's only browser-based async operations, as they execute serially anyway (so the getText() will complete before a subsequent operation?
Presumably if we included non-browser based async operations (e.g. we did a http request to a server), then the ordering wouldn't be guaranteed, so best practice would be to write 'await expect(...).toX(...)' (which is safe even if the expect expression is not async).
Of course, with all that, we end up with 'await' on the beginning of nearly every line, which looks a bit ugly.
expect(await greeting.getText()).toEqual('Hello Julie!');
is the correct way to go.
await stops execution queue and waits until first command is done before moving on to the second one, IN ORDER TO RESOLVE PROMISE. So if your function is synchronous and doesn't return a promise, why await it?
From protractor page, .getText() returns !webdriver.promise.Promise.<string> - long story short, it returns you a promise, thus it needs to be resolved
expect(await greeting.getText()).toEqual('Hello Julie!'); on the other hand returns undefined (try to console.log it). And since it doesn't return promise, and there is nothing to resolve, await is not needed
Additional example
Lets assume you want a synchronous function to take parameters:
someFunction("2" === "1", 1, await $welcomeMessage.getText());
First thing js does, is it runs each argument of the function as a separarte statement. i.e.
"2" === "1" // false
1 // 1
await $welcomeMessage.getText() // 'welcome user'
So by the time when function will be ready to be executed the overall statement will look like so
someFunction(false, 1, 'welcome user');
In other words, even though it looks like the function takes asynchronous promise which you need to wait for, in fact, this promise is resolved before it's executed. So if someFunction itself is synchronous, it doesn't need to be awaited
Protractor is really simple after the introduction of await, don't need to complicate it
First disable selenium control flow in config file, just add this line in config file:
SELENIUM_PROMISE_MANAGER: false
https://www.protractortest.org/#/control-flow
Now in test use:
it('should find an element by text input model', async function() {
await browser.get('app/index.html#/form');
var username =element(by.model('username'));
await username.clear();
await username.sendKeys('Jane Doe');
var name = element(by.binding('username'));
expect(await name.getText()).toEqual('Jane Doe');
});
Note that i am not using await for
var name = element(by.binding('username'));
This is because in protractor the find element action is not triggered unless you call a method on it
so you don't have to use await there
you won't get element not found unless you call any method on it .

Why is the Streamlistener reacting differently?

I'm trying to use the Streambuilder in cooperation with Bloc. The problem is that somehow the UI updates only when the expensive Funktions are finished. It seems that then, and only then updates are made to the stream. But I can not figure out why?
I Implemented a simple Bloc that has 4 events:
1. a Future called over the Bloc Sate Object
2. a Future called inside the Bloc
3. a Funktion called inside the Bloc
4 just using Future.delay
I'm Trying to understand why everything behaves as expectetd, but not when I use first two. My guess is I have a basic misunderstanding of the eventloop but I can not see why there should be a difference in behavior between 2 and 4 or 1 and 4
To make it easy I made an example Project on Github
https://github.com/pekretsc/bloceventloop.git
So I have my refresh methode that ads the new state to the Stream.
if (event is ExpensiveEventInState) {
refresh(BlocUIState.Waiting);
String result = await blocState.doSomeThing();
if (result == '') {
refresh(BlocUIState.Fin);
} else {
refresh(BlocUIState.Fail);
}
}
if (event is ExpensiveEventWhyDoesThisWork) {
refresh(BlocUIState.Waiting);
await Future.delayed(Duration(seconds: 3));
refresh(BlocUIState.Fin);
}
so the question is, should the first and second event not behave the same way?
What happens though is that in the first case the refresh is ignored completely and just the Fin is added to the stream. (I checked that, its not that it is too fast to recognize)
StreamListener's callback is called immediately when an event is pushed on the stream.
On the other hand, StreamBuilder's builder callback isn't. For most common use-cases, it is called at most once per frame.

Await reading document and then setup listener?

Using Flutter and Firestore I frequently setup this block of code.
DocumentReference reference = Firestore.instance.collection('movies').document(uid);
reference.snapshots().listen((documentSnapshot) {
<respond to updates>
});
This fires the listen for the initial read and any changes.
However sometimes I want to do an await for the first read and then setup the listener for changes. How can I do that? Specifically how do I await for the first read, and second make the listen not fire unless there are any changes?