9

I ran into a situation which requires me to popup a window for user to make a choice, after it's closed, based on the user input and make another http request. I don't know how to do a await after the popup.

async function checkRemote(url1, url2)  {

    var resp
    resp = await fetch(url1).then(r => r.json())

    if (r.condition1 == 100) {
        setState({showPopup: true}) //in a reactjs app
        //how do I do await here to wait for the popup being closed
        //get the user choice in variable "proceed"
    }
    if (proceed) {
        resp = await fetch(url2)
        //do some more work
    }
}
6
  • 1
    What is setState ? Commented Jun 24, 2018 at 19:47
  • 1
    Is this React code? If so, please indicate that. Commented Jun 24, 2018 at 19:48
  • It is probably a React app. What is the Popup component looks like? Commented Jun 24, 2018 at 19:48
  • Thanks guys for pointing it out. It's a reactjs app. It's updated to reflect this now in the code snippet. The popup component is a simple one that has essentially "yes", "no", "cancel". Commented Jun 24, 2018 at 20:13
  • You should define a callback to execute from the popup when it's done. Commented Jun 24, 2018 at 20:14

5 Answers 5

7

Create a promise, resolve it inside popup closed event handler, and await for it inside your function.

var popupClosed = new Promise(function(resolve, reject) {
   // create popup close handler, and call  resolve in it
});

async function checkRemote(url1, url2)  {

    var resp
    resp = await fetch(url1).then(r => r.json())

    if (r.condition1 == 100) {
        setState({showPopup: true}) //in a reactjs app
        var closed = await popupClosed;
    }
    if (proceed) {
        resp = await fetch(url2)
        //do some more work
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

can you give a dummy handler which calls resolve in it?
4

Based on @hikmat-gurbanli's answer, here is a working solution. The idea is to save the resolve function so some handle can call it in the future to unblock the async function.

const fetch = require('node-fetch')

var savedResolve;

test("http://localhost/prod/te.php");

async function test(url) {
    await checkRemote(url)
    console.log("completed")
}
var popupClosed = new Promise(function(resolve, reject) {
   // create popup close handler, and call  resolve in it
   console.log("got here")
   savedResolve = resolve;
});

async function checkRemote(url1)  {
    var resp
    resp = await fetch(url1).then(r => r.text())
    console.log("resp " + resp)

    //setState({showPopup: true}) //in a reactjs app
    var result = await popupClosed;
    console.log("result: ")
    console.log(result)
}

A handler can just call savedResolve.resolve("Yes") and it will unblock the async function checkRemote at line var result = await popupClosed;

1 Comment

im trying to do pretty much exactly this, also within react, but im getting issues with my handler when i try to resolve the function, i cant do a savedResolve.resolve() it says its not a function, and if i try to do just savedResolve() it doesnt do anything afterwards, and it wont console log anything
3

Simple implementation with helpers

let passNextStep = false

$('#user-input').click(() => passNextStep = true)

async function myFunc() {
    // do stuff before
    await waitUserInput() // wait until user clicks
    // do stuff after
    // waitUserInput() can be reused as needed
}

myFunc()



// -------------- Helpers --------------

async function waitUserInput() {
    while (passNextStep === false) await timeout(50)
    next = false
}

async function timeout(ms) {
    return new Promise(res => setTimeout(res, ms))
}

Please see this working snippet

// this is an async timeout util
const timeout = async ms => new Promise(res => setTimeout(res, ms));

let next = false; // this is to be changed on user input
let n = 1;

async function waitUserInput() {
    while (next === false) await timeout(50); // pause script but avoid browser to freeze ;)
    next = false; // reset var
}

async function myFunc() {
    $('#text').append(`* waiting user input...<br>`)
    await waitUserInput();
    $('#text').append(`* user has clicked ${n++} time(s)<br>`)
    myFunc()
}

$('#user-input').click(() => next = true)

myFunc()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id='user-input' style='padding:15px;color:white; background: tomato; border: 0; border-radius:8px; font-weight: bold'>CLICK ME !</button>
<div id='text'>
</div>


Further improvements: store the user value

The variable next could be used to store the user input value like this:

const userResponse = await waitUserInput(); // get user input value

// this is an async timeout util
const timeout = async ms => new Promise(res => setTimeout(res, ms));

let next = false; // this is to be changed on user input

async function waitUserInput() {
    while (next === false) await timeout(50); // pause script but avoid browser to freeze ;)
    const userInputVal = next;
    next = false; // reset var
    return userInputVal;
}

async function myFunc() {
    $('#text').append(`* waiting user input...<br>`)
    const userResponse = await waitUserInput();
    $('#text').append(`* user choice is ${userResponse}<br>`)
    myFunc()
}

$('#user-input').click(function() { next = $('#text-input').val() })

myFunc()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id='text-input' type='text'/> 
<button id='user-input' style='padding:15px;color:white; background: tomato; border: 0; border-radius:8px; font-weight: bold'>SUBMIT !</button>
<div id='text'>
</div>

5 Comments

im confused, wouldnt the while function always be calling the timeout since next === false evaluates to true? i dont understand how when next === true it actually calls the timeout() function. Also, how would you do this so that instead of just detecting a click, you could detect which of 2 options they clicked? what is returned from the promise?
For the first question, the function is awaiting since next is false. When user click, next is true and the rest of the fn will be executed and so the rest of the script (check the snippet if it's not clear). For the 2nd question, change the next value by the user value. next = 'myChoice'. This code will still work (admitting the user value cannot be false XD)
right, next is false, but doing a while(next === false) evaluates to true, so it proceeds to await, which is just a 50ms timeout before promise resolves itself... i feel like im missing something heere as to how it;s working. I can see it;s working in the example but i dont understand how the await is working in the while()
This approach may work with jquery but its not working within my react component, im trying to use the promise in the way they described it in Hikmats answer, though i still havent gotten it to work either. the functions seem to just never proceed from the awaits, even after the promise is resolved
You have to be sure all functions in call stack are async and all are awaited for it to work (I remind having hard times with react and async functions) Also since it's in a while loop, it will trigger the timeout until the while condition is false. Also the only purpose of timeout(50) is juste to not freeze the process with an infinite loop
3

This is a very minimalistic example where an async function waits for user input without polling, the promise gets resolved on a button click in this example:

async function testFunction(){
   debug.log("some code");
   await waitForContinue(); //wont continue past this point, unless the continue button is pressed
   debug.log("some other code");
}

function waitForContinue() {
   return new Promise(resolve => {
      document.getElementById("Continue").addEventListener('click', function (e) {
         resolve();
      }, { once: true }); //Event listener is removed after one call
   });
}

1 Comment

+1 - I came back to use my (maximalist) example in this thread, and it was terrible. I was going to edit it to be minimal, but yours is great. I deleted mine. Thanks.
2

I spent a lot of time in this thread -- much of it trying to use .catch correctly. Thanks to all. Here is a minimal program that awaits on controls (buttons) and uses .then and .catch.

<!DOCTYPE html>
<html>
  <head>
    <title> await on button </title>
    <meta charset="UTF-8">    
    <script>
  "use strict"; 
  let fnresolve, fnreject; // the functions are saved here
  let nres=0, nrej=0; 
window.onload = async function() {  
  zlog (''); // 'push either button'
  while (true) {
    let p = new Promise((res, rej) => { fnresolve = res; fnreject=rej; } );
    await p
      .then( (what) => { nres+=1; zlog(what); } )
      .catch((what) => { nrej+=1; zlog(what); } );
  }
}
function zlog(msg) {
  if (msg!='') document.getElementById('zlog').innerHTML += nres+' resolves, '+nrej+' rejects, this one was '+msg+'<br />';
  document.getElementById('zlog').innerHTML += 'push either button<br />';
}
    </script>
  </head>
  <body>
<button onclick='fnresolve("OK");'> RESOLVE </button>
<button onclick='fnreject("NG");''> REJECT </button><br /><br />
<div id='zlog'></div>
  </body>
</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.