I was writing a function in dart that would delete an object from a browser-side Indexed DB, when I discovered that I had to return an outer function value from within an inner function:
Future<bool> delete() {
Transaction tx = db.transactionStore(storeName, "readwrite");
ObjectStore os = tx.objectStore(storeName);
os.delete(_key); // returns blank future, modifies tx
// This is not correct, but shows the idea:
if (tx.onComplete) {return true;}
if (tx.onError) {return false;}
}
This function is a method for a class that I am using to save and load to the Indexed DB.
I want this function to return true
or false
, or a Future object containing the same, when the delete operation succeeds or fails. However, the bottleneck is the os.delete(_key);
statement: it returns a future, but the actual success or failure of the delete operation is provided by tx.onComplete
and tx.onError
. Both of these Objects are streams, so I need to create anonymous functions that handle events from them:
tx.onComplete.listen((e){
return_to_outer_function(true);
});
tx.onError.listen((e){
return_to_outer_function(false);
});
return_to_outer_function(bool) {
return bool; // doesn't work
}
As you can see, when I create anonymous functions, the return statement no longer completes the method, but the inner function. I could have the inner functions call other functions, but then those other functions have return statements of their own that don't return a result to the whole method.
I tried the approach of setting temporary variables and periodically checking them, but it's a very inelegant solution that I don't want to have to use, not just for potential bugs, but because it would hog up the single threaded event loop.
Is it possible to return a value to an outer function from an inner function? Or is there some other, better way to get a value from the presence or absence of events from a set of streams? Or is there another way of using IndexedDB that will avoid this problem?
You can use a Completer
for this.
Future<bool> delete() {
Completer completer = new Completer();
Transaction tx = db.transactionStore(storeName, "readwrite");
ObjectStore os = tx.objectStore(storeName);
tx.onError.first((e){
//return_to_outer_function(false);
completer.complete(false);
});
tx.onComplete.first(bool) {
//return bool; // doesn't work
completer.complete(true)
}
os.delete(_key); // register listeners and then do delete to be on the save side
return completer.future;
}
you then call it like
delete().then((success) => print('succeeded: $success'));
see also https://api.dartlang.org/apidocs/channels/be/dartdoc-viewer/dart:async.Completer