Change the asynchronous jQuery Dialog to be synchronous?
目前,我正在用jquery对话框替换"alert"/"confirm"。
但大多数遗留代码都是以异步方式编写的,这使得更改非常困难。有没有办法使jquery对话框以同步方式工作?(不使用循环或回调函数)
1 2 3 4 5 6 7 | For example: function run() { var result = confirm("yes or no"); alert( result ); \\more codes here } |
在本例中,警报和其他代码将在用户选择后执行。
如果我们使用jquery对话框var result=$dialog.open()。它将继续执行异步警报。
目前,我的解决方案是在OK Cancel函数中使用回调函数。例如:
1 2 3 4 5 6 | OK: function () { $dialog.close(); alert("yes"); //more codes here } |
这种方法是可行的,但是很难使所有的同步代码变成异步的,这需要大量的更改(参见下面的示例)。所以我在寻找同步jquery对话框,这是可能的吗??
例如:(实际代码比下面的示例复杂得多)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function f1() { if ( confirm("hello") ) f2(); alert("no"); } function f2() { if( confirm("world") ) f3(); alert("no"); } function f3() { return confirm("!") ; } |
另一个例子:
1 2 3 4 5 6 7 8 | vendorObject.on('some-event', function() { if(confirm("Do you really want to do that?")) { return true; } else { return false; // cancel the event } }); |
…这里,vendor对象触发一个事件,如果用户确认,则必须取消该事件。只有当事件处理程序同步返回
简短的回答是不,您将无法保持代码同步。这就是为什么:
- 为了实现同步,当前正在执行的脚本必须等待用户提供输入,然后继续。
- 当当前有一个正在执行的脚本时,用户无法与UI交互。事实上,在脚本执行完成之前,用户界面甚至不会更新。
- 如果脚本在用户提供输入之前无法继续,而用户在脚本完成之前无法提供输入,则最接近的是挂起的浏览器。
要演示此行为,请调试代码并在更改UI的行后面的行上设置断点:
1 2 | $("body").css("backgroundColor","red"); var x = 1; // break on this line |
请注意,您的页面背景还没有变红。在您继续执行并且脚本完成执行之前,它不会变为红色。当使用调试器暂停脚本执行时,也无法单击页面中的任何链接。
对于
好消息是,转换代码并不难。大概,您的代码目前看起来是这样的:
1 2 3 4 5 6 7 | if (confirm("continue?")) { // several lines of code if yes } else { // several lines of code if no } // several lines of code finally |
您的异步版本可以创建一个函数
1 2 3 4 5 6 7 8 9 | ifConfirm("continue?", function () { // several lines of code if yes }, function () { // several lines of code if no }, function () { // several lines of code finally }); |
编辑:对于您添加到问题中的其他示例,很遗憾,代码需要重构。不可能有同步的自定义确认对话框。要在事件需要继续或取消的情况下使用自定义确认对话框,您只需始终取消该事件并在
例如,链接:
1 2 3 4 5 6 7 | $("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; }); }); |
或者,一种形式:
1 2 3 4 5 6 7 | $("form").submit(function (e) { e.preventDefault(); var form = this; ifConfirm("Are you sure you're ready to submit this form?", function () { form.submit(); }); }); |
我不确定不使用回调背后的动机是什么,所以很难判断什么解决方案可以满足您的需求,但是延迟执行的另一种方法是通过jquery的"延迟"对象。
http://api.jquery.com/category/deferred-object/
您可以设置一个打开jquery对话框的函数,并添加"等待"对话框关闭的代码。这最终会以一种与回调非常相似的方式工作,在您已经布置好的情况下,但下面是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | function confirm () { var defer = $.Deferred(); $('Do you want to continue?').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); }); }); }); |
它在jsfiddle中工作:http://jsfiddle.net/fjmuj/
不,您不能在javascript中执行任何同步操作(实际上,警报正在破坏规则)。javascript是以"单线程、异步"为核心构建的。
但是,您可以做的是禁用底层页面的功能(类似于lightbox),这样在不执行对话框操作(无论是确定还是取消)之前,不会从页面触发任何事件。认为这不能帮助您使同步代码正常工作。你必须重写。
这里有一些想法-你真正想要的是阻止你的异步事件,让它看起来像是同步的。以下是一些链接:
排队异步调用
莫布尔
叙述性JavaScript
希望这对你有进一步的帮助!!
要回答DavidWhiteman更具体的问题,下面是我如何实现LinkButton单击事件的"延迟"回发。基本上,我只是在阻止默认行为,并在用户反馈可用时手动触发回发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | function MyClientClickHandler(event, confirmationMessage, yesText, noText) { // My LinkButtons are created dynamically, so I compute the caller's ID var elementName = event.srcElement.id.replace(/_/g, '$'); // I don't want the event to be fired immediately because I want to add a parameter based on user's input event.preventDefault(); $('<p> ' + confirmationMessage + ' </p>').dialog({ buttons: [ { text: yesText, click: function () { $(this).dialog("close"); // Now I'm ready to fire the postback __doPostBack(elementName, 'Y'); } }, { text: noText, click: function () { $(this).dialog("close"); // In my case, I need a postback when the user presses"no" as well __doPostBack(elementName, 'N'); } } ] }); } |
我不明白为什么您反对使用jquery回调来实现示例中的行为。您肯定需要重写一些代码,但类似于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | function f1() { $("#testdiv" ).dialog({ modal: true, buttons: { "OK": function() { $( this ).dialog("close" ); f2(); }, Cancel: function() { $( this ).dialog("close" ); alert('no'); } } }); } function f2() { $("#testdiv2" ).dialog({ modal: true, buttons: { "OK": function() { $( this ).dialog("close" ); f3(); }, Cancel: function() { $( this ).dialog("close" ); alert('no'); } } }); } function f3() { $("#testdiv3" ).dialog({ modal: true, buttons: { "OK": function() { $( this ).dialog("close" ); }, Cancel: function() { $( this ).dialog("close" ); } } }); } |