如何在异步函数中使用 JavaScript 等待用户输入

问题描述 投票:0回答:5

我遇到了一种情况,需要我弹出一个窗口供用户做出选择,在窗口关闭后,根据用户输入并发出另一个http请求。我不知道如何在弹出窗口后等待。

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
    }
}
javascript reactjs asynchronous async-await
5个回答
6
投票

创建一个承诺,在弹出关闭事件处理程序中解决它,并在函数中等待它。

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
    }
}

4
投票

根据@hikmat-gurbanli的回答,这是一个可行的解决方案。这个想法是保存解析函数,以便将来某个句柄可以调用它来解锁异步函数。

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)
}

处理程序只需调用

savedResolve.resolve("Yes")
,它将在第
checkRemote
 行解锁异步函数 
var result = await popupClosed;


3
投票

借助助手实现简单

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))
}

请参阅此工作片段

// 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>


进一步改进:存储用户价值

变量

next
可用于存储用户输入值,如下所示:

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>


1
投票

这是一个非常简约的示例,其中异步函数等待用户输入而不进行轮询,在此示例中单击按钮即可解决承诺:

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
投票

我在这个线程中花了很多时间——其中大部分时间试图正确使用 .catch。谢谢大家。这是一个等待控件(按钮)并使用 .then 和 .catch 的最小程序。

<!DOCTYPE html>
<html>
  <head>
    <title> await on button </title>
    <meta charset="UTF-8">    
    <script src="/cssjsphp/incjs1.js"></script>
    <script>
  "use strict"; 
  let fnresolve, fnreject, nres=0, nrej=0; // globals
window.onload = async function() {  
  zlog (1,'push either button'); 
  while (true) {
    let p = new Promise((res, rej) => { fnresolve = res; fnreject=rej; } );
    await p
      .then( (what) => { nres+=1; zlog(2,what); } )
      .catch((what) => { nrej+=1; zlog(2,what); } );
  }
}
function zlog(typ,msg) {
  if (typ==2) 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>
© www.soinside.com 2019 - 2024. All rights reserved.