B4J Tutorial [BANano] [SOLVED] What is the right way to use BANano.WaitFor?

Mashiane

Expert
Licensed User
Ola

This post here bears reference, https://www.b4x.com/android/forum/threads/banano-resumeable-sub-sort-of.100500/#content

I am wondering...

1. Can one define a ???Wait method that can have a BANanoPromise inside it or even a BANanoFetch inside it ? for example.

B4X:
public Sub GetFBTokenWait(resolve As Object)
    Dim stoken As String = ""
    Dim tThen As Object
    Dim tErr As Map
    Dim token As BANanoPromise = firebase.messaging.getToken
    token.Then(tThen)
    stoken = tThen
    token.Else(tErr)
    stoken = ""
    token.End
    banano.Resolve(stoken)
End Sub
Update: This is transpiled to

B4X:
// [461] public Sub GetFBTokenWait(resolve As Object) 
this.getfbtokenwait=async function(_resolve) {
if (_B==null) _B=this;
var _m,_tthen,_terr,_token;
// [462]  Dim m As Map = CreateMap() 
_m={};
// [463]  Dim tThen As Object 
_tthen={};
// [464]  Dim tErr As Map 
_terr={};
// [465]  Dim token As BANanoPromise = firebase.messaging.getToken 
_token=_B._firebase._messaging.gettoken();
// [466]  token.Then(tThen) 
_token.then(function(_tthen) {
// [467]  Log(tThen) 
console.log(_tthen);
// [468]  m.Put( {220} , tThen) 
_m["token"]=_tthen;
// [469]  token.Else(tErr) 
}).catch(function(_terr) {
// [470]  m.Put( {221} , {222} ) 
_m["token"]="";
// [471]  token.End 
});
// [472]  banano.Resolve(m) 
_resolve(_m);
// End Sub
};

And then call it like this?

B4X:
Dim fbToken As String = ""
banano.WaitFor(fbToken, Me, "getfbtokenwait", Null)
Log("Wait response: " & fbToken)
Update: This is being transpiled to:

B4X:
// [377]  Dim fbTokenResult As Map 
_fbtokenresult={};
// [378]  banano.WaitFor(fbTokenResult, Me, {193} , Null) 
_fbtokenresult=await new Promise(function(resolve) {_B[("getfbtokenwait").toLowerCase()](resolve)});
// [379]  Log( {194} & fbTokenResult) 
console.log("Wait response: "+_fbtokenresult);
Whilst in debug mode I am getting a blank response, in release mode Im getting...

B4X:
Uncaught (in promise) ReferenceError: _resolve is not defined
I'm sure i'm doing something wrong somewhere and could use some green lights on this.

Thanks
 
Last edited:

Mashiane

Expert
Licensed User
Update, interesting observation.

I decided to log the token just after tThen, and it seems to process it accordingly, however there is this _resolve issue.

1612400466325.png


Thanks

Update: Release code

B4X:
this.getfbtokenwait = async function (__8d9) {
    if (_B == null) _B = this;
    var _m, __8d6, _terr, __81b;
    _m = {};
    __8d6 = {};
    _terr = {};
    __81b = _B.__347.__35c.gettoken();
    __81b.then(function (__8d6) {
        _m["token"] = __8d6;
    }).catch(function (_terr) {
        _m["token"] = "";
    });
    _resolve(_m);
};
PS: If possible and it wont break implementations, is it possible to make the Obfuscation a TranspilerOption that can be turned on/off by the developer just like LiveCodeSwapping? Thanks.
 
Last edited:

alwaysbusy

Expert
Licensed User
The _resolve in Release mode is a bug and will be fixed in the next update.

WaitFor was a first trial to do promises (2018), but one should just use BANanoPromise as it is much better. Most important reason one should not use WaitFor is because it can only Resolve, not Reject.

Your mistake was here the 'when' to resolve:
B4X:
public Sub GetFBTokenWait(resolve As Object)
    Dim stoken As String = ""
    Dim tThen As Object
    Dim tErr As Map
    Dim token As BANanoPromise = firebase.messaging.getToken
    token.Then(tThen)
        stoken = tThen
    token.Else(tErr)
        stoken = ""
    token.End
    ' will run BEFORE the token promise is resolved
    banano.Resolve(stoken)
End Sub
Correct code would be:
B4X:
public Sub GetFBTokenWait(resolve As Object)
    Dim tThen As Object
    Dim tErr As Map
    Dim token As BANanoPromise = firebase.messaging.getToken
    token.Then(tThen)
         banano.Resolve(tThen)
    token.Else(tErr)
         banano.Resolve("")
    token.End
End Sub
But because of the WaitFor Reject limitation, you will have to check after the GetFBTokenWait if the result is "" or something.

Two BANanoPromise alternatives, from which the second one is the best:
B4X:
' ALT 1: same prinsiple as WaitFor, so also same restriction. Can be useful if the Promise always returns a Resolve/BANano.ReturnThen()
Dim fbToken As String = ""
Dim promToken As BANanoPromise
promToken.CallSub(Me, "getfbtokenwait", Null)
' will pause your code here
fbToken = BANano.Await(promToken) ' The return promise can NOT use a Reject, only a Resolve! (same restriction as a Waitfor)
    
Log("Wait response 1: " & fbToken)

' ALT 2: Best as it uses Resolve/BANano.ReturnThen() and Reject/BANano.ReturnElse()    
Dim fbToken As String = ""
Dim promToken As BANanoPromise
promToken.CallSub(Me, "getfbtokenwait", Null)
' will NOT pause your code here
promToken.ThenWait(fbToken)
    Log("Wait response 2a: " & fbToken)
promToken.ElseWait(fbToken)
    Log("Wait response 2b: " & fbToken)
promToken.End
    
' will be printed BEFORE repsonse 2a or 2b
Log("Wait response 3: " & fbToken)
output order:
Wait response 1:
Wait response 3:
Wait response 2a/2b:

I think in the long run .WaitFor will be depreciated as the BANanoPromise is a much better alternative.

Alwaysbusy
 

Mashiane

Expert
Licensed User
In my case, I guess because the code after getting the token is dependent on getting the token first, I will have to go with the first option of "pausing the code"

So that the process is completed before the processing i.e. subscription is done using the token. At least I can show a loading indicator on my button until the process is done.

This is how I have implemented it as I have to wait for the token first to be able to subscribe to topics.

B4X:
Dim fbToken As String = ""
    Dim promToken As BANanoPromise
    promToken.CallSub(Me, "GetFBToken", Null)
    ' will pause your code here
    fbToken = banano.Await(promToken)
    Log(fbToken)
and

B4X:
public Sub GetFBToken As String
    Dim tThen As Object
    Dim tErr As Map
    Dim token As BANanoPromise = firebase.messaging.getToken
    token.Then(tThen)
    banano.ReturnThen(tThen)
    token.Else(tErr)
    banano.ReturnElse("")
    token.End
End Sub
Thanks a lot.

I want to test if this can work inside a library so that I just get the token string.
 

Mashiane

Expert
Licensed User
In my case, I guess because the code after getting the token is dependent on getting the token first, I will have to go with the first option of "pausing the code"

So that the process is completed before the processing i.e. subscription is done using the token. At least I can show a loading indicator on my button until the process is done.

This is how I have implemented it as I have to wait for the token first to be able to subscribe to topics.

B4X:
Dim fbToken As String = ""
    Dim promToken As BANanoPromise
    promToken.CallSub(Me, "GetFBToken", Null)
    ' will pause your code here
    fbToken = banano.Await(promToken)
    Log(fbToken)
and

B4X:
public Sub GetFBToken As String
    Dim tThen As Object
    Dim tErr As Map
    Dim token As BANanoPromise = firebase.messaging.getToken
    token.Then(tThen)
    banano.ReturnThen(tThen)
    token.Else(tErr)
    banano.ReturnElse("")
    token.End
End Sub
Thanks a lot.

I want to test if this can work inside a library so that I just get the token string.
 

alwaysbusy

Expert
Licensed User
Will not work. As said, if you use BANano.Await, you can NOT use BANano.ReturnElse. It will raise errors if the token promise fails.

guess because the code after getting the token is dependent on getting the token first, I will have to go with the first option of "pausing the code"
No, it just means you have to reorganize your code so everything that is 'after the promise' must be moved inside the .Then().

Alwaysbusy
 
Top