使用异步函数等待用户从 onclick 输入

Aar*_*ano 13 javascript callback event-handling dom-events async-await

我是 async 的新手,也许只是没有围绕基本原理,但我试图通过调用一个弹出模式并等待用户提交数据的异步函数来等待来自 onclick 的用户输入。在找到一两个甚至提到使用异步来等待对我的特定任务没有特别帮助的页面事件的来源之后……我想出了这个:

asnyc func1 (){
  var userInput = await async2();

  //do stuff with user input
}
async func2(){
  //build modal content specific to task
  //display modal
  return new Promise(function(resolve,reject){
       $(document).on('click', '#save-input', function(e){
          var input = $('#input-data').val();
          resolve(input);
      });
  });
}
Run Code Online (Sandbox Code Playgroud)

一切似乎都正确调用,我得到了用户输入,但 func1 永远不会超过对 async2 的调用。所以很明显我错过了这个的一些关键方面,但我似乎无法从我的来源中提取它。

回调不是一个选项,这里的代码比我简短地详细介绍的要多得多,但上面描述的是我需要执行的基线功能。

538*_*MEO 6

简单片段

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); // pauses script
    next = false; // reset var
}
Run Code Online (Sandbox Code Playgroud)

jQuery 的示例用法

// just change the value of `next` for the script to continue
$('#user-input').click(() => next = true);

async function myFunc() {
    // do stuff before
    await waitUserInput(); // wait until user clicks
    // do stuff after
}

myFunc() // launch function and start waiting for user input
Run Code Online (Sandbox Code Playgroud)

请参阅此工作演示

// 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()
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


进一步改进

这个例子可以很容易地改进以满足您的需求。例如,该变量next还可用于存储用户输入值,而 waitUserInput 返回该值。这将导致编写如下内容:

const userResponse = await waitUserInput(); // get user input value
Run Code Online (Sandbox Code Playgroud)

// 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()
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


Kev*_*nTD 6

我搜索了很多,但没有找到任何相关内容,只有这个问题。我想要异步的东西而不依赖循环来检查,所以我做了一个不同的解决方案。

主要问题是使用事件侦听器解决 Promise,因此我在 Promise 中创建了 eventListener 函数,并使用箭头函数来获取 Promise 的上下文。然后我解决了承诺并在第一次单击后取消事件监听器。

为了使函数可被任何侦听器重用,我也为此添加了一个条目。

function waitListener(element, listenerName) {
    return new Promise(function (resolve, reject) {
        var listener = event => {
            element.removeEventListener(listenerName, listener);
            resolve(event);
        };
        element.addEventListener(listenerName, listener);
    });
}
Run Code Online (Sandbox Code Playgroud)

如果您想将其用于某些用途,它将返回该事件。这使您更容易有序地编写一些代码序列。但要工作,它必须位于异步函数内,这意味着该函数将开始并行运行,因此了解从哪里开始非常重要,以免妨碍您的进程。

在一些异步函数中的简单使用:

var element = document.querySelector("button");
await waitListener(element,"click");
Run Code Online (Sandbox Code Playgroud)

完整样本:

function waitListener(element, listenerName) {
    return new Promise(function (resolve, reject) {
        var listener = event => {
            element.removeEventListener(listenerName, listener);
            resolve(event);
        };
        element.addEventListener(listenerName, listener);
    });
}
Run Code Online (Sandbox Code Playgroud)
var element = document.querySelector("button");
await waitListener(element,"click");
Run Code Online (Sandbox Code Playgroud)

如果您需要每次单击按钮时都发生相同的事情,那么最好只使用一个addEventListener。根据您要执行的操作,您可以使用 addEventListener 并使用removeEventListener 在其执行的函数中取消。现在,如果您想做一些取决于事件顺序的事情,也许使用此函数可能是一个很好的解决方案。