【问题标题】:Using jQuery promise to simulate synchronous call使用 jQuery Promise 模拟同步调用
【发布时间】:2014-03-31 16:16:11
【问题描述】:

我一直在使用bootbox.js 库,它是异步操作的,但我需要以同步方式使用它(例如,在提交表单之前放置​​一个“确认”窗口)。

我不想使用e.preventDefault() 取消事件,我想推迟操作,直到用户响应模态。目前该库不支持它,但我很好奇是否可以使用 Promise 模拟同步行为?

这是一个非常基本的示例,使用链接(而不是表单提交按钮,这是我的最终目标): http://plnkr.co/edit/5NovsuKTeQ7y6SKNTwWp?p=preview

【问题讨论】:

  • 我认为你做的方式就是它应该做的方式。你的意思是因为你使用的是对话框而不是 html,所以它很难看?
  • @weeknie - 哪个方向?我使用第一个链接的方式,它不等待模态 - 这是我认为承诺可能有助于模拟第二个链接的同步性的地方。
  • 您可以做的不是使用提交的表单,而是直接使用模态,当用户单击模态的“确认”时,您可以捕获数据并用它做你想做的事.或者你可以看看这个答案:stackoverflow.com/questions/1205044/…
  • 有趣——所以你建议让页面上的按钮/链接/任何元素只调用模态,然后在模态中使 OK/Yes 按钮具有实际事件?我想我必须制作一个自定义对话框才能这样做,这就是为什么我希望使用承诺或其他方式来延迟默认操作。
  • 这是一个适用于 bootbox https://stackoverflow.com/a/68394453/14697989 的工作解决方案

标签: javascript jquery promise


【解决方案1】:

不,这根本不是承诺的作用。 Promise 在这里无法为您提供帮助。

链接的默认操作是导航到另一个页面(或转到此页面中的某个部分)。如果您想阻止链接执行其操作 - 您必须使用 e.preventDefault() 或从 onclick 处理程序(最好是前者)返回 false。

preventDefault 正是您所需要的,听起来完全符合您的目标。

但是confirm 有效吗?!

是的,确实如此,没有人真正知道为什么 - 阻塞是 confirm promptalert 的原始行为,并且它从未因向后兼容性而改变。它完全阻塞并且在它启动时没有任何反应 - 这与语言和其他 API 不同,并且非常不典型。 - 例如:

setTimeout(function(){ 
    alert("World");
},100);
alert("Hello");

在这里,"World" 在您关闭“Hello”框之前不会被提醒,即使它只有 100 毫秒的超时。 alerts 和 prompts 只是“冻结”JavaScript 执行。它们被认为是糟糕的用户体验,除了非常具体的问题外,通常是一个糟糕的选择。

那么什么是承诺?

Promises 是对延迟计算的抽象,它们允许您创建看起来像同步的异步代码,这很棒,但它们并不神奇,它们不会将代码变成 实际上 em>同步。所有 Promise 所做的只是让编写异步代码几乎像编写同步代码一样简单

【讨论】:

  • OK——表单提交请求有很多参数。有没有办法抓住这个复杂的动作(可能来自e)并“保存”以备后用?
  • @pennstatephil 您可以自己在表格上致电submit()document.getElementById("yourFormId").submit() :)
  • 提交按钮上有一个参数(例如,在表单上多次提交“保存”与“提交”),但我想我可以抓住该参数并稍后将其放入请求中。感谢您的回复。
  • 您也可以使用闭包并将该代码放入请求中 - 没有害处。这里的问题是 preventDefault() 是一个同步调用,提交带有模式确认的表单是异步的。
  • 我以前用过这个,但它不适用于我在同事网站上遇到的特定情况:gist.github.com/pennstatephil/9896793
【解决方案2】:

我遇到了同样的问题,我找到的一个解决方案是使用隐藏按钮:

<button id="submit" type="submit" style="display:none;">x</button>
<button id="send_submit" type="button">y</button>

然后在js代码中,

$("#send_submit").click(function(e){
    bootbox.confirm("Really want to do this ?", function(result){
        if(result)
            $("#submit").click();
    })
})

这不是一个漂亮的方法,但它可以像你想要的那样工作,其他方式就像你说的那样,使用prevenDefault on事件,并将所有传入的数据逐个捕获以使用.post发送它们;

【讨论】:

    【解决方案3】:

    我也在使用 Bootbox 时遇到过这个问题。我就是这样解决的。

    看看这个删除表单:

    <form action="route/to/action" method="POST">
      <!-- these two instructions depend on your framework -->
      @method('DELETE')
      @csrf
    
      <!-- The submit button in the form, change it to type="button". -->
      <!-- This prevent the form submission without the user's confirmation. -->
      <button type="button" id="delete" title="Delete element">
        Delete
      </button>
    </form>
    

    然后,添加一个点击事件监听器以编程方式调用submit() 事件。

      let deleteButton = document.getElementById('delete');
    
      deleteButton.addEventListener('click', (ev) => {
        bootbox.confirm('Delete this element?', (confirma) => {
          if (confirma) {
            return $(ev.target)[0].form.submit(); 
          }
        })
      });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-25
      • 1970-01-01
      • 2015-05-31
      • 2019-04-01
      • 2016-07-30
      相关资源
      最近更新 更多