0

I'm making a dialog box in a HTML layer in Javascript. When I call it, I want it to behave just like when I call the built-in Alert box. It should yield the GUI thread when called, and then resume execution on the next code line when it is closed down. From the caller's perspective, it acts as if it blocks the GUI thread. Is this possible in Javascript?

In the main function below, I want the execution state of the function to be preserved right when showDialog is called. The dialog is then shown, and receives click events, etc, and when it finally closes down, I want the return value to be passed back to the result variable and execution resumes in the main function. Is this possible somehow? I am not taking about actually blocking the GUI thread, because then the dialog would not work.

function main()
{
  // Show the dialog to warn
  let result = showDialog("Warning", "Do you want to continue?", ["OK", "Cancel"]);

  // Do some stuff.
  if (result === "OK") performAction(); 
}

// This function shows a custom modal dialog (HTML layer), and should only return the GUI 
// thread when the user has clicked one of the buttons.
function showDialog(title, text, buttons)
{
  // Code here to draw the dialog and catch button events.
}

Björn Morén
  • 693
  • 5
  • 14
  • does this solve your problem? https://stackoverflow.com/questions/6807799/stop-page-execution-like-the-alert-function – Shubham Apr 13 '20 at 09:31
  • Thanks @Shubham. It kind of does. I know about promises and callback methods. That's what I currently use to solve the problem. But I think it makes the code ugly and hard to read. So I was hoping I could make some clever use of the yield keyword, but I haven't figured it out. – Björn Morén Apr 13 '20 at 10:56

2 Answers2

2

It turns out that async/await can do just what I need. Calling a function using the await keyword will "block" the thread at that point, until the function's promise is resolved. To be able to use the await keyword, the main function must use the async keyword.

async function main()
{
  let dialog = new CustomDialog();
  let result = await dialog.show();
  if (result === "OK") performAction();
}

class CustomDialog
{
  constructor()
  {
    this.closeResolve = null;
    this.returnValue = "OK";
  }
  show()
  {
    // Code to show the dialog here

    // At the end return the promise
    return new Promise(function(resolve, reject) 
    { 
      this.closeResolve = resolve; 
    }.bind(this));
  }

  close()
  {
     // Code to close the dialog here

     // Resolve the promise
     this.closeResolve(this.returnValue);
  }
}

Björn Morén
  • 693
  • 5
  • 14
1

Due to Javascript nature you can't block the code. The only way is using a timer to check the return value, promises or, the better solution for this, a callback:

function main()
{
  showDialog({
    title: "Warning", 
    text: "Do you want to continue?", 
    buttons: ["OK", "Cancel"],
    onClose: function(result) {
      if (result == "OK") {
        performAction1();
      } else {
        console.log("Cancelled");
      }
    }
  });
}

function showDialog(options)
{
   $("#dialog .title").innerText = options.title;
   $("#dialog .text").innerText = options.text;
   $(".button").hide();
   for (var i = 0; i < options.buttons.length; i++) {
     $(".button:nth-child(" + i + ")")
       .show()
       .innerText(options.buttons[i])
       .click(() => {
         $("#dialog").hide();
         options.onClose(options.buttons[0]); // Perform the callback
       }
   }
   #("#dialog").show();
}
ariel
  • 15,620
  • 12
  • 61
  • 73
  • Thanks ariel. I was hoping to avoid callbacks or promises, because they make the code hard to read, especially when your have a sequence of multiple dialogs, but I guess I'm stuck with them for now. – Björn Morén Apr 14 '20 at 04:54