How to return a function value from inside an inner function/stream listener?

dart, dart-async, indexeddb

Solution

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

Problem

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?

Original source