#function #flutter #dart #asynchronous #async-await
Вопрос:
Я написал асинхронную функцию Flutter/Dart, которая, на мой взгляд, ведет себя неожиданно. Следующая структура кода:
static Future<bool> verifySometing() async {
try {
await getCloudData().then((snapshot) {
if (snapshot.exists amp;amp; snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
});
} catch (e) {
print('Error $e');
return false;
}
print('Something went wrong');
return false;
}
Ожидаемым результатом будет то, что функция ожидает облачных данных, затем ожидает проверки и возвращает значение true, если данные действительны. В этом случае консоль покажет следующее, и функция вернет значение true:
Data is correct
На практике происходит то, что консоль показывает следующий вывод, и функция сначала возвращает true, а затем false:
Data is correct
Something went wrong
Это противоречит всему, что я думал знать о функциях в Dart, потому что я всегда предполагал, что после запуска return функция будет выполнена. Есть идеи, как это происходит?
Комментарии:
1. Имейте в виду, что при использовании
await
вам не нужно использоватьthen
и наоборот. Плюсawait
останавливает выполнение кода, освобождая поток для другой работы, и продолжается только тогда, когда ожидаемая работа выполнена. В отличие от тогоthen
, который не останавливает выполнение приведенного ниже кода.
Ответ №1:
Проблема в этой строке.
await getCloudData().then((snapshot) {
Здесь, вместо того, чтобы просто await
отвечать, вы также прикрепили then
обратный вызов. Таким образом, на самом деле, что бы вы ни возвращали, это возвращаемое значение callback
функции, т. Е.,. (snapshot) {}
Функция обратного вызова, которую вам нужно передать, then
берет это return true
и передает нам в результате await
.
Итак, если бы вы поместили что-то вроде
var bool = await getCloudData().then((snapshot) { ..... });
Тогда это bool
было бы равносильно true
. Это оно. Нет возврата от вашей основной функции.
Измените его на этот,
var snapshot = await getCloudData();
if (snapshot.exists amp;amp; snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
Надеюсь, я смог внятно объяснить.
Ответ №2:
В ваших предположениях есть несколько ошибок.
Во-первых, вы прикрепили букву а then
к возвращенному будущему getCloudData()
. Это означает , что вы не ждете getCloudData()
, а вместо этого возвращаете дополнительное будущее getCloudData().then(...)
, и это будущее вернется, когда функция обратного вызова, переданная ему, завершится. (И если первое будущее не выдаст ошибку, будет вызван обратный вызов.)
Во-вторых, функция обратного вызова работает в своей собственной области. Таким образом, этот код делает не то, что вы думаете, что он делает:
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
Это возвращение повлияет на функцию обратного вызова, а не на verifySomething
функцию.
Учитывая это, порядок работы выглядит следующим образом:
validateSomething
Функцияawait
sgetCloudData().then(...)
.getCloudData()
ему звонят.getCloudData()
возвращает, вызывается обратныйthen
вызов, переданный.- (При условии, что снимок содержит данные)
validateData
вызывается. - (При условии, что данные успешно проверены) «Данные верны» печатается, и функция обратного вызова возвращается
true
. validateSomething
получает уведомление о том, что ожидаемое будущее завершено, поэтому выполнение возобновляется.- «Что — то пошло не так» печатается, и
validateSomething
функция возвращаетсяfalse
.
Вообще говоря, такого рода ошибки часто встречаются при смешивании async/await
и then
моделировании. Если вы не знаете, что делаете, придерживайтесь либо одного, либо другого, предпочтительно async/await
шаблона. Например, рефакторинг вашего кода для устранения вызова then
выглядит следующим образом:
static Future<bool> verifySometing() async {
try {
final snapshot = await getCloudData();
if (snapshot.exists amp;amp; snapshot.hasData) {
bool dataValid = await validateData(snapshot.data);
if (dataValid) {
print('Data is correct');
return true;
}
}
} catch (e) {
print('Error $e');
return false;
}
print('Something went wrong');
return false;
}
Теперь, когда нет надоедливого закрытия, с которым нужно иметь дело, return
он вернется, validateSomething
как и ожидалось, и вам не нужно будет решать такие проблемы, как обратные вызовы и область действия.