Javascript executing backwards
Asked Answered
R

1

6

An app is using Cordova with InAppBrowser plugin version 3.2.1 to load a webpage built in Asp.Net 4.5.2. We have been experiencing erratic behaviour, so I've made a page to catch the problem and share it here.

This page contains a really simple button executing JS within the onclick event:

<button onclick="alert('1'); alert('2'); alert('3');"> EXECUTION</button>

It works perfectly, but when the website is embed in the app, the execution order runs backwards, displaying:

  • Alert 3
  • Alert 2
  • Alert 1

Using unobstrusive JS with the same results:

<button id="testButton">Test</button>
$(document).ready(function () {
    $("#testButton").click(function () {
       alert('1');
       alert('2');
       alert('3');
    });
});

Running the website in ios with Safari works perfectly fine.

Any idea?

Update

As suggested by @Bergi in the comments, adding a sleep timeout verifies a problem managing synchronous calls. Following code triggers the alerts in the right order:

$("#testButton").click(function () {
    alert('1');
    setTimeout(function () { alert('2'); }, 2000);
    setTimeout(function(){ alert('3'); }, 4000);
});

But not when the timeouts are closer. The following displays the alerts in wrong order:

$("#testButton").click(function () {
    alert('1');
    setTimeout(function () { alert('2'); }, 1);
    setTimeout(function(){ alert('3'); }, 2);
});

Update 2

As proposed by @Bergi in the comments, I've tried:

$("#testButton").click(function () {
    var x = []; x.push(1); x.push(2); alert(x);
});

With a correct result, displaying an alert containing: "1,2".

Issue has been reported.

Raffin answered 7/7, 2020 at 10:48 Comment(11)
I'd guess their embedding doesn't provide a proper synchronous version of alert, rendering them all at once (on top of each other). You might verify this by trying to add some sleep() calls in between.Kendra
"Any idea?" - don't use alert() :-)Kendra
Thanks, @Kendra for the ideas. The use of alert() is just to simplify the code and share it here. Of course that is not our code in production ;)Raffin
@MarioLevrero Like @Kendra said, you can sleep() or just console.log() to verify. :)Superaltar
Thanks, Bergi and @Muhammad. I've added a sleep using Timeout and now the order is correct.Raffin
@MarioLevrero Are you saying that actual code runs backwards (so this is not an artifact of how alerts are showing)? Please provide that code as wellKendra
@MarioLevrero Like what happens when you do var x = []; x.push(1); x.push(2); alert(x) - does it throw an exception? Or alert 2,1? Or does it work as expected?Kendra
Thanks, @Kendra I've tried with that code (Update 2 in the Q). The execution there is correct.Raffin
The first comment from @Kendra sounds like the answer. Instead of timeouts, you could easily confirm this with some kind of logging or breakpoint in between each alert() call. Does this browser support either console.log or debugger statements? If not, you could put fetch or XMLHttpRequest calls in between to fetch some nonexistent resource on your server, e.g. fetch("log-one"), fetch("log-two"). The fetches will fail with 404 errors, but you can check the server log to see the order they arrived. I'll bet they all arrive in a row before you click on any of the alerts.Caprice
Another possible way to check @Bergi's theory: are the alert boxes draggable? You could move the top one and see if another one shows up behind where it was.Caprice
Or, do the alert boxes automatically size themselves to fit the content? You could put a really long message in the first one, a shorter message in the second, and even shorter in the third. You may get to see all three of them this way.Caprice
C
2

As @Bergi suggests in a comment, the version of alert() you're calling is likely to be asynchronous on some platforms and synchronous on others. This would explain the behavior you're seeing.

Instead of using window.alert() at all, when you need an alert box you should probably use navigator.notification.alert() from cordova-plugin-dialogs.

Note the signature for this function:

navigator.notification.alert( message, alertCallback, [title], [buttonName] )

The alertCallback function gets called after the alert box is dismissed. Even if some implementations are synchronous (because they use the native browser alert() function) and some are asynchronous, navigator.notification.alert() provides a compatible interface for both cases.

Well, mostly compatible. On platforms where navigator.notification.alert() calls the native alert(), the function will not return until the alert box is dismissed by the user. On platforms that use some other implementation, the function may return immediately. But in both cases, alertCallback will be called when the alert box is dismissed.

cordova-plugin-dialogs also provides similar implementations of navigator.notification.confirm() and navigator.notification.prompt(), each with completion callbacks.

There is an interesting bit of code in tests.js from cordova-plugin-inappbrowser:

window.alert = window.alert || navigator.notification.alert;
if (isWindows && navigator && navigator.notification && navigator.notification.alert) {
    // window.alert is defined but not functional on UWP
    window.alert = navigator.notification.alert;
}

Note how this function sets window.alert to be the same as navigator.notification.alert on platforms where there is no window.alert, and also on UWP. While not directly related to your situation, this illustrates how there may be different implementations on different platforms. But using navigator.notification.alert() should let you write compatible code for all. Just don't assume anything about whether this function returns immediately or waits for the alert to be dismissed - use the alertCallback instead.

Caprice answered 13/7, 2020 at 17:30 Comment(2)
Thanks, @Michael. I understand it, but the problem I see then is that the webPage layer must take in account being embedded in the Cordova plugin what I think is against a proper layer design.Raffin
We realized about this alert management when debugging a similar error when using __doPostBack() from an Asp page. Even if Cordova-PlugIn has an implementation for alert() the problem with the __doPostBack would persistRaffin

© 2022 - 2024 — McMap. All rights reserved.