I have a function that returns a future which depends on the result of a callback to resolve:
Future connectSocket(String email, String password, {Function onConnectCallback}) async {
var completer = new Completer();
print("Connecting...");
var query = getQueryString(email, password);
socketIO = await SocketIOManager().createInstance(SocketOptions(localDomainWindows, query: query));
socketIO.on("loginError", (data) {
print("Login err");
_connected = false;
connectedCallback();
completer.complete(false);
});
socketIO.onConnect((data) {
print("***CONNECTED***");
_connected = true;
completer.complete(true);
connectedCallback();
});
socketIO.connect();
return completer.future;
}
I can see ***CONNECTED*** printed to the console, and my socket server acknowledges the connection, but the function await-ing the resolution never resumes, it just hangs.
socketConnection.connectSocket(_email, _password)
.then((success) {
print("SUCCESS") // never gets printed
}
The only possible explanation for this is that some code in the callback is blocking your program from continuing because Completer.complete should otherwise always make the future complete.
If it is blocked, however, the event loop will never be able to call your code.
As a bool assignment should never be blocking (_connected = true;), the only part of your function that could be halting your program is connectedCallack();. If you remove or fix it, you should see your future complete.
Related
hello I want have to run two functions(Function1() and Function2()) and store value of these returns and run third function. But some time according to condition Function1() or Function2() or both not be run.
if(condition1){
await Function1();
}
if(condition2){
await Function2();
}
await Functon3();
I try as above but Function3() run simultaneously with Function1() or with Function2().
My Function1() code looks like following...
Future Function1() async {
apiService
.apiFileUpload()
.then((value) async {
///codes goes here
}).catchError((error) {
print('EEEE: ' + error.toString());
});
}
If anything not clear please let me know in the comment section.
Please do not use .then() in combination with async/await. It is technically possible, but it takes some skill to get it right, so why make it hard on yourself. Stick with one way of doing it, use either one or the other. You mixed it up and through a slight oversight, your Function1 does not actually wait on it's result. It just returns, with the function still running in the then block. So you await it, but that does not help.
Since you are using await already, stick with that and remove .then() from your repertoire for now:
Future Function1() async {
try {
final value = await apiService.apiFileUpload();
///codes goes here
} catch(error) {
print('EEEE: ' + error.toString());
}
}
You can use await
Future Function1() async {
try{
final value = await apiService
.apiFileUpload();
final value2 = await secondFuntion();
///add more and condition on values
} catch(e){
.....
}
}
from your question you need to tell the compiler to stop on particular task with await and avoid using then function it will never stop your compiler
your future fuction:
Future Function1() async {
apiService
.apiFileUpload()
.then((value) async {
///codes goes here
}).catchError((error) {
print('EEEE: ' + error.toString());
});
}
Modified Future func
Future Function1() async {
var result = await apiService.apiFileUpload();
if(result == success){
// code goes here
}else{
//you can show your error here
}
}
In a protractor test, I need to close a pop-up if it appears (it doesn't always) and proceed with the test as normal. Here's the code I've got to do so-
let checkForPopUp = async function() {
element(by.css('button[id="gdprStopEmails"]')).isPresent().then(function (isVisible) {
return isVisible;
});
}
it('description', async function() {
let hasPopUp = await checkForPopUp();
if(hasPopUp) {
await element(by.id("gdprStopEmails")).click();
}
await connectedAccounts.revokePermission(partnerInfo.revokeId, partnerInfo.confirmRevokeId);
});
I ran this test a few times without checking if the element was there, and it closed the popup every time it was there (and failed the test when it wasn't). It hasn't closed the popup a single time since I introduced the condition check, and despite my best efforts I can't figure out what's up. Does anything jump out to you guys? Thanks in advance!
you're missing return. Your function returns nothing explicitly and thus implicitly returns undefined which is always falsy, and your if block doesn't get executed
This should work
let checkForPopUp = async function() {
return element(by.css('button[id="gdprStopEmails"]')).isPresent().then(function (isVisible) {
return isVisible;
});
}
it('description', async function() {
let hasPopUp = await checkForPopUp();
if(hasPopUp) {
await element(by.id("gdprStopEmails")).click();
}
await connectedAccounts.revokePermission(partnerInfo.revokeId, partnerInfo.confirmRevokeId);
});
but since you're using async/await don't mix syntaxes. I'd do it this way
let checkForPopUp = async function() {
return element(by.css('button[id="gdprStopEmails"]')).isPresent()
}
it('description', async function() {
let hasPopUp = await checkForPopUp();
if(hasPopUp) {
await element(by.id("gdprStopEmails")).click();
}
await connectedAccounts.revokePermission(partnerInfo.revokeId, partnerInfo.confirmRevokeId);
});
and keep in mind isPresent doesn't guarantee the visibility
I want to call and wait async function done before return from a sync function
// async function
Future<User> getUser(String username) async {
...
}
In dart, i could use https://api.dart.dev/stable/2.9.2/dart-cli/waitFor.html to wait a async function before go to next statement.
bool checkUser(String username, String encodedPwd) {
var user = waitFor<User>(getUser(username));
if (user.pwd == encodedPwd)
return true;
else
return false;
}
Because the require of the framework, the checkUser function will be call by framework, and must be a sync function.
In flutter, I could not use dart:cli, I implement by pattern .then() .whenComplete(), but when call checkUser the statement print(1) will be call and end the function without wait for getUser finish.
bool checkUser(String username, String pwd) {
getUser(username).then((user) {
if (user.pwd == encodePwd(pwd)) {
return true;
} else {
return false;
}
);
print(1);
}
My question is how to call async function inside sync function and wait the async function done before return.
Thank you.
Being able to do what you ask would basically render the distinction between sync and async functions useless (and block the main thread I think). The function you linked "should be considered a last resort".
I think what you want is :
Future<bool> checkUser(String username, String pwd) async {
var user = await getUser(username);
return user.pwd == encodePwd(pwd) ? true : false;
}
This can be achieved by creating a task, then waiting/yielding for the task to complete. The Yield prevents blocking.
var result = MyAsyncMethod.InvokeAsync(data);
result.Start();
while (result.Status != TaskStatus.RanToCompletion)
{
System.Threading.Thread.Yield();
}
See this code:
class SomeClass{
String someVariable;
SomeClass();
Future<String> getData () async {
Response response = await get('http://somewebsite.com/api/content');
Map map = jsonDecode(response.body); // do not worry about statuscode, trying to keep it minimal
someVariable = map['firstName'];
return 'This is the first name : $someVariable';
}
}
Now look at main:
void main(){
String someFunction() async {
SomeClass instance = SomeClass(); // creating object
String firstNameDeclaration = await instance.getData().then((value) => value);
return firstNameDeclaration;
}
}
When working with Future, like in the case of firstNameDeclaration why do I have to use .then() method to access the string object, since I am waiting for the function to finish?
When searching on the web, some people use .then() others don't, I am confused.
Kindly help me have a clearer understanding of how Futures and async functions overall work.
Background
Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:
Fetching data over a network.
Writing to a database.
Reading data from a file.
To perform asynchronous operations in Dart, you can use the Future class and the async and await keywords.
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
Futures vs async-await
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
async-await is just a a declarative way to define asynchronous functions and use their results into Future and it provides syntactic sugar that help you write clean code involving Futures.
Consider this dart code snipped involving Futures -
Future<String> getData(int number) {
return Future.delayed(Duration(seconds: 1), () {
return 'this is a future string $number.';
});
}
main(){
getData(10).then((data) => {
print(data)
});
}
As you can see when you use Futures, you can use then callback when the function return a future value. This is easy to manage if there is single "then" callback but the situation escalates quickly as soon as there are many nested "then" callbacks for example -
Future<String> getProductCostForUser() {
return getUser().then((user) => {
var uid = user.id;
return getOrder(uid).then((order) => {
var pid = order.productId;
return getProduct(pid).then((product) => {
return product.totalCost;
});
});
});
}
main(){
getProductCostForUser().then((cost) => {
print(cost);
});
}
As you can when there multiple chained "then" callback the code become very hard to read and manage. This problem is solved by "async-await". Above chained "then" callbacks can be simplified by using "async-await" like so -
Future<String> getProductCostForUser() async {
var user = await getUser();
var order = await getOrder(user.uid);
var product = await getProduct(order.productId);
return product.totalCost;
}
main() async {
var cost = await getProductCostForUser();
print(cost);
}
As you can above code is much more readable and easy to understand when there are chained "then" callbacks.
I hope this explains some basic concepts and understanding regarding the "async-await" and Futures.
You can further read about topic and examples here
Basically, you should either use await OR then(). However, Dart guidelines advocates that you should prefer use await over then() :
This code :
Future<int> countActivePlayers(String teamName) {
return downloadTeam(teamName).then((team) {
if (team == null) return Future.value(0);
return team.roster.then((players) {
return players.where((player) => player.isActive).length;
});
}).catchError((e) {
log.error(e);
return 0;
});
}
should be replaced by :
Future<int> countActivePlayers(String teamName) async {
try {
var team = await downloadTeam(teamName);
if (team == null) return 0;
var players = await team.roster;
return players.where((player) => player.isActive).length;
} catch (e) {
log.error(e);
return 0;
}
}
In your case, you should write :
void main(){
Future<String> someFunction() async {
SomeClass instance = SomeClass(); // creating object
String firstNameDeclaration = await instance.getData();
return firstNameDeclaration;
// Or directly : return await instance.getData();
// Or : return instance.getData();
}
}
getData() async {
http.Response response = await http.get('https://www.example.com/);
print(response.body);
}
The above function works to get the HTML code of a page but it fails in some cases. The function is sometimes never completed and it waits forever to get response( For example, if the app is opened while internet is off and even when its turned on, it never connects). In such situations is there any way to retry ?
I tried the http retry package but it gives me 15+ errors.
Example code for how this could be done:
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List> loadData() async {
bool loadRemoteDatatSucceed = false;
var data;
try {
http.Response response = await http.post("https://www.example.com",
body: <String, String>{"username": "test"});
data = json.decode(response.body);
if (data.containsKey("success")) {
loadRemoteDatatSucceed = true;
}
} catch (e) {
if (loadRemoteDatatSucceed == false) retryFuture(loadData, 2000);
}
return data;
}
retryFuture(future, delay) {
Future.delayed(Duration(milliseconds: delay), () {
future();
});
}
You can use RetryPolicy from http package to retry your connection, just create your own class and inherit form RetryPolicy and override these function like the following example, then create a Client using HttpClientWithInterceptor.build and add your custom retryPolicy as a parameter, this will retry your request for a number of times until a condition is met, if not, it'll just stop retrying.
import 'package:http/http.dart';
class MyRetryPolicy extends RetryPolicy {
final url = 'https://www.example.com/';
#override
// how many times you want to retry your request.
int maxRetryAttempts = 5;
#override
Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async {
//You can check if you got your response after certain timeout,
//or if you want to retry your request based on the status code,
//usually this is used for refreshing your expired token but you can check for what ever you want
//your should write a condition here so it won't execute this code on every request
//for example if(response == null)
// a very basic solution is that you can check
// for internet connection, for example
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
return true;
}
return false;
} on SocketException catch (_) {
return false;
}
}
}
then create and use a client to make your requests.
it will automatically retry the request if the condition you wrote is met.
Client client = HttpClientWithInterceptor.build(
retryPolicy: ExpiredTokenRetryPolicy(),
);
final response = await client.get('https://www.example.com/);
there is also a package to check for internet connection if that your problem, see connectivity
You can use try-catch blocks inside async functions like you would in synchronous code. Perhaps you'd be able to add some sort of error handling mechanism in the function, and retry the function on error? Here's some documentation on that one.
Example from the docs:
try {
var order = await getUserOrder();
print('Awaiting user order...');
} catch (err) {
print('Caught error: $err');
}
You can also catch specific Exceptions, per this github issue.
doLogin(String username, String password) async {
try {
var user = await api.login(username, password);
_view.onLoginSuccess(user);
} on Exception catch(error) {
_view.onLoginError(error.toString());
}
}
EDIT: This may also help.
While we're at it, look here for a function that reattempts an async operation however many times you need.