Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 320
Skyler827 Avatar asked Sep 03 '25 03:09

Skyler827


1 Answers

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

like image 91
Günter Zöchbauer Avatar answered Sep 04 '25 23:09

Günter Zöchbauer