There is another way to write a inline asyncronous function in dart? - flutter

var a = await () async {try{return await ... }}.call();
I was thinking that way to write is not convenient, they are so verbose.
"await () async {...}" is a very ugly style.
What I'm wrong? There is another way to do this?
var a = await () async
{
try {
return await method();
} catch (e) {
return anotherMethod();
}
}.call();
EDIT:
The return inside the try block send the value to a variable "a". Otherwise, I had to: First: declare a variable Then: set the value inside the try-catch block.
This kind of structure can easily drive you to fail, once that you don't have any guarantee that the variable are true set.
By the other hand: with an inline function you have to return any value otherwise the compile alert by the ERROR. And you get a more refactorable code;

Related

Flutter function returning at await statement

I am using flutter with the cbl package to persist data. Trying to retrieve the entries does not seem to work because the function created is returning at the await statement and not the return statement. This does not seem like the intended result of darts async/await functionality. So I am lost.
task_database.dart
Future<dynamic> getAllTasks() async {
final tasksDb = await Database.openAsync(database); <---------- Returns here
var tasksQuery = const QueryBuilder()
.select(SelectResult.all())
.from(DataSource.database(tasksDb));
final resultSet = await tasksQuery.execute();
late var task;
await for (final result in resultSet.asStream()) {
final map = result.toPlainMap();
final taskDao = TaskDao.fromJson(map);
task = taskDao.task;
// Do something with the task...
print(task);
}
;
return task; <-------------------------------------------- Does not make it here
}
task_cubit.dart
getAllTasks() => {
allTaskMap = TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
What I have tried. I have tried to use Database.openSync instead of Database.openAsync however, the function just returns at the next await statement. I have also tried making getAllTasks asynchronous and awaiting the database as such.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
However this has the same issue, when the function from task_database returns prematurely it the returns at the first await function in getAllTasks which is the allTaskMap variable.
Thanks
A function cannot "return prematurely" without a return statement.
The only way the execution is cut short would be an exception being thrown.
I also don't see how you don't get syntax errors, when you don't await the Database.openAsync(database) statement.
So make sure all your awaits are in place. Use the linter to find those that are missing. While you are at it, remove the keyword dynamic from your vocabulary, it will only hurt you if you use it without a need for it. Your return type should be properly typed, then your compiler could tell you, that returning a single task from a function that is clearly supposed to return multiple tasks is not going to work.
Either catch your exceptions and make sure you know there was one, or do not catch them and watch them go all the way through into your debugger.
In addition, following the comment of #jamesdlin, your function definitions are... valid, but probably not doing what you think they are doing.
Future<void> getAllTasks() async => {
allTaskMap = await TasksAbcDatabase().getAllTasks(),
emit(TaskState(tasks: state. Tasks))
};
needs to be
Future<void> getAllTasks() async {
allTaskMap = await TasksAbcDatabase().getAllTasks();
emit(TaskState(tasks: state. Tasks));
}

Wait for query inside for loop - Flutter Firebase

I have this function that creates a list of users from their ids. A query is made for each id to get the information from Firebase RTDB.
static List<FrediUser> formattedParticipantListFromIDs(List<String> participantIDs) {
List<FrediUser> formattedParticipants = [];
for (String id in participantIDs) {
dbQuery(2, 'users', id).once().then((value) {
formattedParticipants.add(FrediUser.fromMap(value.snapshot.value as Map));
});
}
print(formattedParticipants.length);
Future.delayed(const Duration(seconds: 3), () {
print(formattedParticipants.length);
});
return formattedParticipants; }
Output of 1st print statement
0
Output of 2nd print statement
3
The Problem
The return is always an empty list. As you can see, the loop and the return statement do not wait for the list to be populated. BUT, if you wait 3 seconds, the list did get populated, but it is too late.
How can I wait, in each iteration of the for loop, for the query to be done AND the .then to be called and completed?
*This method is called in a factory constructor function of a class, therefore futures and awaits cannot be used.
You'll want to use await to wait for the asynchronous once() method.
// 👇
static Future<List<FrediUser>> formattedParticipantListFromIDs(List<String> participantIDs)
async {
// 👆
List<FrediUser> formattedParticipants = [];
for (String id in participantIDs) {
// 👇
var value = await dbQuery(2, 'users', id).once();
formattedParticipants.add(FrediUser.fromMap(value.snapshot.value as Map));
}
print(formattedParticipants.length);
return formattedParticipants;
}
As you'll see, this means that your formattedParticipantListFromIDs function has to be marked as async, and returns a Future. There is no way to prevent this, as there's no way to make asynchronous code behave synchronously.
For more on this, I recommend taking the Dart codelab on Asynchronous programming: futures, async, await

Rewrite sort((a, b) =>) to being async [duplicate]

I have this code :
widget.items.sort((a, b) {
await getItemDistance(a, true);
await getItemDistance(b, false);
return (itemADistance)
.compareTo(itemBDistance);
});
I am trying to sort widget.items list based on values returned from getItemDistance. However I get an error with a red squiggly line that says :
The await expression can only be used in an async function
and when I try to add async to the sort method I get another red squiggly line that says :
The argument type 'Future Function(Item, Item)' can't be assigned
to the parameter type 'int Function(Item, Item)'
How do I solve this dilemma guys ? :)
Thanks
List.sort is a synchronous function that expects a synchronous callback; there is no way to use it with an asynchronous callback. I would recommend transforming your List and doing any necessary asynchronous work first and then synchronously sorting the results. Doing so also should avoid calling getItemDistance (which, by virtue of being asynchronous, is likely to be expensive) on the same item multiple times. For example, something like:
final computedDistances = <Item, double>{};
for (final item in widget.items) {
final distance = await getItemDistance(item, ...);
computedDistances[item] = distance;
}
widget.items.sort((a, b) =>
computedDistances[a].compareTo(computedDistances[b])
);
(I don't know what the second argument to getItemDistance represents; if you can't get around that, you would need to build one Map with getItemDistance(..., true) results and one with getItemDistance(..., false) results1.)
As a last resort, you could write your own asynchronous sort function.
Edit #1
This should be a more efficient version since it doesn't wait for each asynchronous operation one-by-one:
final computedDistances = await Future.wait<double>([
for (final item in widget.items) getItemDistance(item, ...),
]);
final computedDistancesMap = <Item, double>{
for (var i = 0; i < widget.items.length; i += 1)
widget.items[i]: computedDistances[i],
};
widget.items.sort((a, b) =>
computedDistancesMap[a].compareTo(computedDistancesMap[b])
);
Edit #2
I've added a List.sortWithAsyncKey extension method to package:dartbag that can do this :
await widget.items.sortWithAsyncKey(
(element) => getItemDistance(element, ...),
);
1 However, if you need to call getItemDistance(..., true) for the first argument and getItemDistance(..., false) for the second argument, that implies that your comparison function probably is not self-consistent.
Whenever you are running async code you should add the async keyword like below. this tells dart you intend to run async code.
Async functions return a Future which tells dart that at some point in the future you are expecting itemADistance or an error.
You will want to return a Future of type int since you are expecting to receive an int itemADistance or an error.
Future<int> widget.items.sort((a, b) async {
await getItemDistance(a, true);
await getItemDistance(b, false);
return (itemADistance)
.compareTo(itemBDistance);
});

contact_services getContactsForPhone returing Future<dynamic> instead of String - Flutter

I am trying to get Contact using the function getContactsForPhone
getName()async{
number = '123-456-7890'
return await ContactsService.getContactsForPhone(number).then((value) => value.elementAt(0).displayName.toString());
}
but I am getting Future<dynmaic> instead of .displayName which is supposed to be String
You are mixing it up two way's to use Futures:
You can use await keyword to await for the conclusion.
You can use the then method to have a callback when the Future ends.
You need to choose one and stick with it. Using the await is always preferable because it makes the code more readable and avoids some callback hells.
In your case:
Future<String> getName() async {
number = '123-456-7890'
Iterable<Contact> myIterable = await ContactsService.getContactsForPhone(number);
List<Contact> myList = myIterable.toList();
return myList[0].displayName.toString()
}
Which should return the DisplayName you wanted.
Remember to also use the await keyword from the outside, wherever you call this function.
You can read more about Future and Asynchronous code here.

How to cleanly extract a callback out of a when.js promise?

I need to pass a callback to a function whose signature is function('ui', {foo: bar, callback: callbackfn}). The function I want to pass is a When.js promise.
The best I've come up with:
var d = when.defer();
var p = when(d);
var q = p.then(function() {
return loadItem(newCatalogItem, name, fileOrUrl);
});
ConfirmationMessage.open('ui', { callback: d.resolve });
return q;
This works (using a deferred to prevent immediate execution, and then passing the resolve function as the callback), but seems a bit convoluted.
Is there a cleaner way?
I think you want to just promisify that ConfirmationMessage.open method (see also the when.js docs here and there), and then use it like a promise function, chaining then calls onto it.
For your specific example, that could be (using the portable promise constructor):
return when.promise(function(resolve) {
ConfirmationMessage.open('ui', { callback: resolve });
}).then(function(confirmResult) {
return loadItem(newCatalogItem, name, fileOrUrl);
});