你能等待javascript回调吗?

IT技术 javascript jquery dialog callback confirm
2021-03-16 20:37:21

我正在尝试使用http://abeautifulsite.net/notebook/87 中的 jQuery 警报对话框库而不是默认警报(在我看来这看起来很糟糕)。这似乎是一个很棒的库,但是没有如何使用 jConfirm 库的示例。

我需要做这样的事情:

function confirm() {
        var result = false;
        var response = false;
        jConfirm('are you sure?', 'Confirmation Dialog',
          function(r) {
            result = r;
            response = true;
            return r;
        });
        if (response == true) {
            alert(result);
            return result;
        }
        else {
            //wait for response
            alert('hi');
        }
    }

和我从我的 .net 按钮打来的电话:

我在插件的网站上发表了评论(就在今天早上),并在 Google 上搜索了 javascript 并等待回调完成但没有结果。

在 javascript 的其余部分执行之前,关于如何正确使用回调来获得结果的任何想法?

谢谢。

6个回答

你刚刚在 JavaScript 中遇到了一个很大的限制。一旦您的代码进入异步世界,就无法回到经典的过程执行流程。

在您的示例中,解决方案是创建一个循环以等待响应被填充。问题是 JavaScript 没有提供任何指令,允许您在不占用 100% 处理能力的情况下无限循环。因此,您最终会阻止浏览器,有时会导致您的用户无法回答实际问题。

这里唯一的解决方案是坚持异步模型并保持它。我的建议是,您应该向任何必须执行一些异步工作的函数添加回调,以便调用者可以在您的函数结束时执行某些操作。

function confirm(fnCallback) 
{
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) 
    {
        // Do something with r 

        fnCallback && fnCallback(r); // call the callback if provided
    });
}

// in the caller

alert('begin');

confirm(function(r)
{
    alert(r);

    alert('end');
})
@dkretz:当然,这是 Javascript 的限制(如上所述;现在在 2019 年有所不同)。是的,为了方便用户,网页是异步工作的。但是事件循环并不是进行异步编程的唯一方法。
2021-04-21 20:37:21
语言的限制是无法在保持相同上下文的同时让步给浏览器。如果这是可能的,我们可以写“doAjax(); while( !ajaxDone() ){ Sleep(); }”。但这在 Javascript 中是不可能的,因为没有 Sleep 或类似的功能......
2021-04-30 20:37:21
异步和程序模型的伟大概念化。通常很多人的代码是两者的混合,并且没有意识到如何解决只需要使用一个的问题,就像我在阅读此答案之前的情况一样;)
2021-05-05 20:37:21
这不是 javascript 中的限制。这是 html 网页的工作方式。与javascript无关。
2021-05-07 20:37:21
jConfirm('are you sure?', 'Confirmation Dialog',
    function(r) {
        result = r;
        response = true;
        return r;
    }
);
if (response == true) {

这暴露了对使用异步代码发生的事件序列的误解。仅仅因为你已经内联编写它并不意味着它会严格地从上到下执行。

  1. jConfirm 被调用,接收一个函数作为它的参数之一,它记住了。
  2. jConfirm 在页面上显示其 UI 并立即返回。
  3. 'if (response==true)' 行执行。真的这应该只是读“如果(响应)”,布尔比较是多余的。但无论如何,回应当然是错误的。您的函数放弃并退出,将控制权交还给浏览器。
  4. 用户单击 jConfirm 的 UI。
  5. jConfirm 现在才开始行动并回调你给它的函数,它早先记住了。
  6. 您的嵌套函数将 response 设置为 true,对于 'if (response==true)' 条件来说为时已晚,无法对其执行任何操作。

您已经编写了“//wait for response”作为替代方案,但是您无法编写实际执行此操作的 JavaScript 代码。您的函数必须返回以将控制权交还给浏览器,然后浏览器才能在 jConfirm UI 上触发单击事件以继续处理。

存在使异步代码在同步上下文中工作(反之亦然)的方法 - 特别是线程和协程(以及它们有限的关系生成器)。但是 JavaScript 没有这些功能,因此您必须编写代码以适合您的库使用的同步或异步模型。

这是一个很好的答案。但是关于如何构造回调的一些代码呢?
2021-04-21 20:37:21

由于回调是异步的(至少,从某种意义上说,它正在等待用户做某事),因此在回调中处理您需要的内容可能会更容易:

function confirm() {
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) {
        if (r) doSomething();
    });
}

@klogan [评论]

我猜你是从这里得到的

该页面为您提供了答案:(在Usage下查看

这些方法不会返回与 confirm() 和 prompt() 相同的值。您必须使用回调函数访问结果值。(有关更多详细信息,请参阅演示。)


@klogan

我想说明的一点是,并没有真正简单的方法来完成您想要的。您正在尝试将过程事件驱动的编程相关联——JavaScript 无法帮助您做到这一点。

最简单(虽然有风险)的解决方案是使用伪无限循环。但是,如果callback永远不会被调用,您现在就有了一个真正的无限循环。而且,根据 JavaScript 引擎,您可能会终止浏览器的等待。

要点:最好的办法是避免 这种 将事件驱动强制转换为程序的尝试。

function confirm() {
    var result = false;
    var response = false;

    jConfirm('are you sure?', 'Confirmation Dialog',
      function(r) {
        result = r;
        response = true;
    });

    while(!response) continue; // wait
    return result;
}

无限循环不起作用。JavaScript 是单线程的;当 while 循环旋转时,jQuery 的确认 UI 甚至无法与之交互。
2021-04-25 20:37:21
谢谢,我实际上尝试了 while 循环来测试该解决方案,但是 IE 会抛出一个警告对话框,说 javascript 正在挂起。你说得对,我不想那样做。我会等待作者的消息并发布解决方案。也许他们自己还没有完成。
2021-04-26 20:37:21
我确实从他们的网页上得到了答案。
2021-05-06 20:37:21
并且他们的演示代码没有显示如何使用确认结果
2021-05-10 20:37:21
感谢您的响应,但我需要该函数从回调函数返回结果。所以如果用户点击ok -> return true,如果用户点击cancel -> return false。然后这将像内置的确认功能一样工作。
2021-05-14 20:37:21

从技术上讲,是的,但我不会在网站上这样做。

看看基于Narcissus 的Narrative JavaScript

Narrative JavaScript 是 JavaScript 语言的一个小扩展,它支持异步事件回调的阻塞功能。这使得异步代码具有令人耳目一新的可读性和可理解性。

Selenium使用这种技术。


更新

查看JavaScript 链

JavaScript Strands 为 JavaScript 语言添加了协程和协作线程支持,以启用异步事件回调的阻塞功能。这使得利用异步操作的代码更加线性、可读和可管理。Strands 建立在由 Neil Mix 编写的 Narrative JavaScript 之上,并且大部分 Narrative JavaScript 都保留在 Strands 中,包括本文档的大部分内容。

在 JavaScript 中,您的代码不能简单地等待事件触发——该事件必须始终由单独的异步事件处理程序处理。有时这很好,但它经常迫使应该是简单的语句序列变成粗糙的扭曲。它还破坏了封装功能的能力,因为调用函数必须知道提供回调处理程序。Strands 提供了挂起和恢复执行线程的能力。当事件完成时,执行可以暂停恢复。这允许您在封装实现的简单、线性、可读的代码中编写难以阅读的异步事件处理。

您指向 Javascript Strands 的链接已失效。太糟糕了,因为这听起来很有趣。
2021-04-24 20:37:21

我假设你必须抓住这样的回应。我认为你不需要回调。

function confirm() {
        var response = jConfirm('are you sure?', 'Confirmation Dialog');
        if (response) {
            alert(result);
        }
        else {
            //wait for response
            alert('hi');
        }
    }
不幸的是,该插件不返回变量。这是我开始使用它时所期待的。
2021-05-15 20:37:21