There are some questions posted about uploading multiple files to Firebase, but all the solutions I came across use a forEach loop or something similar to upload one by one. However, if I'm uploading files that depend on each other (say, my app requires both of them to exist to function correctly), this could be an issue because one of the uploads could succeed and the other fail.
I thought there must be a way to do something similar to a batch write in Firestore but for uploading files in Firebase Storage.
Is there any way to do that or is the loop method the only way?
(I'm using Flutter, so if possible I would appreciate it if any code provided as an answer is written in Dart)
Well, you could use Future.wait() to upload your files simultaneously without waiting for any of them to complete before you begin other.
To explain further, I made the following code snippet, please follow along:
void main() {
Future.wait([
uploadImage1(),
uploadImage2(),
uploadImage3(),
]);
}
Future<void> uploadImage1() async {
await Future.delayed(Duration(seconds: 3), () {
print('1');
});
}
Future<void> uploadImage2() async {
throw Exception();
}
Future<void> uploadImage3() async {
await Future.delayed(Duration(seconds: 3), () {
print('3');
});
}
I made three async operations, and added them all to Future.wait list, so all are executed/triggered at the same time, doesn't matters if any of them fails. Try the code on dart pad and you will see the output appears at the same time, the output would look like:
1
3
: ExceptionError: Exception
On the other hand, if you want to wait for one operation to successfully finish, then you can use await on a method that returns Future, so it will wait until the operation is successfully completed.
void main() async {
await uploadImage1();
await uploadImage2();
await uploadImage3();
}
Future<void> uploadImage1() async {
await Future.delayed(Duration(seconds: 3), () {
print('1');
});
}
Future<void> uploadImage2() async {
throw Exception();
}
Future<void> uploadImage3() async {
await Future.delayed(Duration(seconds: 3), () {
print('3');
});
}
The output would be:
1
: ExceptionError: Exception
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
}
}
I was testing a service I wrote which returns a Future, but this weird behavior happened when I awaited the result of the future and the test never completed. Trying to reproduce the error in a minimal way, I got this:
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('...',
(WidgetTester tester) async {
print('awaiting');
await Future.delayed(Duration(seconds: 2)); // never completes
print('done'); // not reached
});
}
but this completes normally:
import 'package:flutter_test/flutter_test.dart';
void main() {
test('...',
() async {
print('awaiting');
await Future.delayed(Duration(seconds: 2)); // completes normally
print('done'); // prints "done"
});
}
why is the first one not completing, what am I missing?
using tester.runAsync solves the problem (I still don't know why I need to run my function within this function). It is used like this as per this github issue:
await tester.runAsync(() async {
// run my function here
});
Looking for help here guys. I have 2 Futures that populate data in sqflite. I need one (_insertInitialData()) to finish first before calling the second one (_insertAdditionalData()). I have done it this way, but it's not working. It first does the re-recreation of the DB as expected, then both _insertInitialData() and _insertAdditionalData() not in the order I expected. I have tried .whenComplete and calling here _insertAdditionalData() and also have tried different ways that I think should work but nothing.
This is just something I'm doing for fun but still I'd like to know what I'm doing wrong.
TIA
Future<void> _insertAdditionalData() async{}
void populateDB() {
try {
final localDB = LocalDatabase.instance;
Future.wait([localDB.dropDB(recreateDB: true)]).then((_){
print('DB recreated!');
Future.wait([_insertInitialData()]).then((_) {
print('_insertInitialData done');
Future.wait([_insertAdditionalData()]).then((_){
print('_insertAdditionalData done');
});
});
});
} catch (ex) {
print('There was a problem in populateDB(): $ex');
}
}```
Using await makes things a lot easier to read and will block execution of later lines until the action has finished.
Future<void> populateDB() async {
final localDB = LocalDatabase.instance;
await localDB.dropDB(recreateDB: true);
print('DB recreated!');
await _insertInitialData();
print('_insertInitialData done');
await _insertAdditionalData();
print('_insertAdditionalData done');
}
You can try using only one future statement, and follows it with multiple "then". This makes sure the first "then" will be completed before the second "then" is executed. I assume your localDB.dropDB(recreateDB: true) function is asynchronous.
Future<void> _insertAdditionalData() async{}
void populateDB() {
try {
final localDB = LocalDatabase.instance;
localDB.dropDB(recreateDB: true).then((_){
print('DB recreated!');
}).then((_) {
_insertInitialData();
print('_insertInitialData done');
}).then(() {
_insertAdditionalData();
print('_insertAdditionalData done');
});
} catch (ex) {
print('There was a problem in populateDB(): $ex');
}
}
Cool. Thanks for your comments. I replaced all of those Future.wait for async/await even in my internal methods that insert into the DB and it's all good!!! (executing in the sequence I need)
Just learning Dart/Flutter for fun and I love it.
I have 2 functions. I want to run them one by one but while the first function is done, the second function must wait for 1-2 seconds. I tried Future.delayed for this but it did not work. It changes nothing.
void kartat(int tip, int deger, int mainid, List mycards) {
masadakicards.add(cardbank[mainid]);
print("kart atıldı");
rakipkartat(51);
}
void rakipkartat(int mainid) {
new Future.delayed(Duration(seconds: 1), () {
// deleayed code here
masadakicards.add(cardbank[mainid]);
print("ann");
});
}
A way that you can achieve this is by using await Future.delayed
make sure that your method is returns a Future
Future<void> start() async {
await foo();
await Future.delayed(Duration(seconds: 2));
await bar();
}
Future<void> foo() async {
print('foo started');
await Future.delayed(Duration(seconds: 1));
print('foo executed');
return;
}
Future<void> bar() async {
print('bar started');
await Future.delayed(Duration(seconds: 1));
print('bar executed');
return;
}
expected:
foo started
- waits 1 second -
foo executed
- waits 2 seconds -
bar started
- waits 1 second -
bar executed
Following your methods
Please note that the method that gets executed after the delay also needs to include async and await, otherwise the method will run synchronously and not await the Future.
Future<void> start() async {
foo();
}
void foo() {
Future.delayed(Duration(seconds: 2), () async {
// do something here
await Future.delayed(Duration(seconds: 1));
// do stuff
});
}
Not sure if your overall approach is appropriate (can't tell from this), however,
Future<void> rakipkartat(int mainid) async { should do.
I guess it would be better if you create both and the calling function as Future and then call the functions with await kartet(); await rakipkartat()
By the way, implementing my 1st paragraph also requests that the calling function is a Future or at least handles the call as a Future.
I am updating my document with this code.
Future<void> save() async {
print('league save');
final DocumentReference ref =
Firestore.instance.collection('leagues').document(_documentName);
Firestore.instance.runTransaction((Transaction tx) async {
DocumentSnapshot postSnapshot = await tx.get(ref);
if (postSnapshot.exists) {
await tx.update(ref, _getDocument());
print('league save complete');
}
});
}
I believe that this may be failing sometimes but I am not sure. I am got getting an error.
The reason I suspect it is failing sometimes is because my listener (elsewhere in the app) isn't always getting fired when the document changes.
How do I log or capture an error in the transaction?
runTransaction is just a normal async operation that you can follow up with a then and catchError:
Firestore.instance.runTransaction((Transaction tx) async {
// do whatever
}).then((val) {
// do something upon success
}).catchError((e) {
// do something upon error
});
and you can skip then .then() if you want