将异步jQuery对话框更改为同步?

use*_*284 37 javascript jquery asynchronous dialog synchronous

目前,我正在努力用jquery对话框替换"alert"/"confirm".

但是大多数遗留代码都是以某种异步方式编写的,这使得它很难改变.有没有办法让jquery对话框以同步方式工作?(不要使用循环或回调函数)

   For example:
   function run()
   { 
      var result = confirm("yes or no");
      alert( result );
      \\more codes here
   }
Run Code Online (Sandbox Code Playgroud)

在此示例中,警报和其他代码将在用户选择后执行.

如果我们使用jquery对话框var result = $ dialog.open()它将继续执行异步警报.

目前,我的解决方案是在OK | Cancel功能中使用回调函数.例如:

    OK: function ()
   {
       $dialog.close();
       alert("yes");
       //more codes here
    }
Run Code Online (Sandbox Code Playgroud)

此方法有效,但很难使所有同步代码变为异步,这需要进行大量更改(请参阅以下示例).所以我正在寻找同步jQuery Dialog,它可能吗?

例如:(实际代码比下面的例子复杂得多)

     function f1()
    {
          if ( confirm("hello") )    f2();
          alert("no");
    } 

    function f2()
    {
          if( confirm("world") )    f3();
          alert("no");
    }

    function f3()
    {
          return confirm("!") ;
    }
Run Code Online (Sandbox Code Playgroud)

另一个例子:

vendorObject.on('some-event', function() {
    if(confirm("Do you really want to do that?")) {
        return true;
    }
    else {
        return false; // cancel the event
    }
});
Run Code Online (Sandbox Code Playgroud)

...此处供应商对象触发一个事件,如果用户确认,该事件必须被取消.只有事件处理程序返回false- 同步时才能取消该事件.

gil*_*ly3 35

简短的回答是否定的,您将无法保持代码同步.原因如下:

  • 为了使其同步,当前正在执行的脚本必须等待用户提供输入,然后继续.
  • 虽然存在当前正在执行的脚本,但用户无法与UI进行交互.实际上,在脚本执行完之后,UI才会更新.
  • 如果脚本无法继续,直到用户提供输入,并且用户在脚本完成之前无法提供输入,则您将获得的最接近的是挂起的浏览器.

要说明此行为,请调试代码并在更改UI的行后面的行上设置断点:

$("body").css("backgroundColor", "red");
var x = 1;  // break on this line
Run Code Online (Sandbox Code Playgroud)

请注意,您的页面背景还不是红色.在您恢复执行并且脚本完成执行之前,它不会更改为红色.当您的调试器暂停执行脚本时,您也无法单击页面中的任何链接.

这个规则有一个例外,alert()confirm().这些是浏览器控件,其处理方式与实际网页UI元素不同.

好消息是转换代码真的不是很难.据推测,您的代码目前看起来像这样:

if (confirm("continue?")) {
    // several lines of code if yes
}
else {
    // several lines of code if no
}
// several lines of code finally 
Run Code Online (Sandbox Code Playgroud)

你的异步版本可以创建一个函数ifConfirm(text, yesFn, noFn, finallyFn),你的代码看起来非常相似:

ifConfirm("continue?", function () {
    // several lines of code if yes
},
function () {
    // several lines of code if no
},
function () {
    // several lines of code finally 
});
Run Code Online (Sandbox Code Playgroud)

编辑:回答您添加到问题中的其他示例,遗憾的是,该代码需要重构.根本不可能有同步自定义确认对话框.要在事件需要继续或取消的场景中使用自定义确认对话框,您只需要始终取消事件并模拟yesFn回调中的事件.

例如,一个链接:

$("a[href]").click(function (e) {
    e.preventDefault();
    var link = this.href;
    ifConfirm("Are you sure you want to leave this awesome page?", function () {
        location.href = link;
    });
});
Run Code Online (Sandbox Code Playgroud)

或者,表格:

$("form").submit(function (e) {
    e.preventDefault();
    var form = this;
    ifConfirm("Are you sure you're ready to submit this form?", function () {
        form.submit();
    });
});
Run Code Online (Sandbox Code Playgroud)


Ben*_*n L 8

我不确定不使用回调的动机是什么,因此很难判断哪种解决方案可能满足您的要求,但延迟执行的另一种方法是通过jQuery的"延迟"对象.

http://api.jquery.com/category/deferred-object/

您可以设置一个打开jquery对话框的函数,并添加"等待"对话框关闭的代码.在您已经布局的情况下,这最终会以与回调相似的方式工作,但这是一个示例:

    function confirm () {
        var defer = $.Deferred(); 
        $('<div>Do you want to continue?</div>').dialog({
                autoOpen: true,
                close: function () { 
                    $(this).dialog('destroy');
                },
                position: ['left', 'top'],
                title: 'Continue?',
                buttons: {
                    "Yes": function() {
                        defer.resolve("yes"); //on Yes click, end deferred state successfully with yes value
                        $( this ).dialog( "close" );
                    },
                    "No": function() {
                        defer.resolve("no"); //on No click end deferred successfully with no value
                        $( this ).dialog( "close" );
                    }
                }
            });
        return defer.promise(); //important to return the deferred promise
    }

    $(document).ready(function () {
        $('#prod_btn').click(function () {
            confirm().then(function (answer) {//then will run if Yes or No is clicked
                alert('run all my code on '  + answer);

            });
        });

    });
Run Code Online (Sandbox Code Playgroud)

这里是在jsFiddle工作:http: //jsfiddle.net/FJMuJ/

  • 问题在于,不能改变的现有组件和接口取决于呼叫的同步性质.例如,我必须在事件处理程序中"返回false",具体取决于用户是选择"是"还是"否"或其他按钮. (2认同)

小智 3

不,你不能在 Javascript 中执行任何同步操作(事实上,警报违反了规则)。Javascript 的核心是“单线程、异步”。

不过,您可以做的是禁用基础页面(类似灯箱)的功能,因此在您不执行对话框操作(无论是“确定”还是“取消”)之前,页面不会触发任何事件。认为这不能帮助您使同步代码正常工作。你必须重写。