2016-07-30 114 views
1

我需要做的这个帖子的对立面,“Best way to iterate over an array without blocking the UI如何阻止用户界面长期运行的JavaScript循环

我通过数百行必须循环,并为每一个值。但是,在我允许用户执行下一步并将更新的行提交到数据库之前,该工作必须完成。

JavaScript代码如下。

// toolbar events/actions 
changeZeroDiscountButton.click(function (event) { 
    var value = discountComboBox.jqxComboBox('val'); 

    if ((value != null) && (value != "")) { 
     value = value/100; 

     // get all the rows (this may have to be changed if we have paging 
     var datainformations = $('#jqxgrid').jqxGrid('getdatainformation'); 
     var rowscounts = datainformations.rowscount; 

     for (var i = 0; i < rowscounts; i++) { 
      var preSetDiscount = $("#jqxgrid").jqxGrid('getcellvalue', i, "discount"); 

      if (preSetDiscount == .0000) { 
       $("#jqxgrid").jqxGrid('setcellvalue', i, "discount", value); 
      } 
     } 
    } 

}); 
+0

你使用引导? – jonju

+0

Sorta。它是Joomla组件的一部分,Joomla支持一些Bootstrap功能。 – NJA

回答

0

JavaScript的设计,因此不会阻止任何方式的用户界面,这也是其最重要的特点之一浏览器。唯一的例外是弹出消息框(即alert(),confirm()propmpt())。即使有可能,也不建议阻止用户界面。

有很多替代方法可以防止用户发起不应该被解雇的行为,直到发生其他事情。示例:

  • 禁用操作按钮,直到您的处理结束然后启用它。
  • 设置一个标志(例如var processing = true)并在动作按钮的单击事件中检查该标志,以便在标志为true时显示消息(例如“仍在处理中,请稍候......”),并在标志执行时执行动作是false。切记不要使用alert()作为消息,否则您将阻止处理。改为使用弹出式div
  • 将处理开始时的事件处理程序设置为显示消息的函数(例如“仍在处理中,请稍候...”),并在处理结束时将事件处理函数设置为将会做这个动作。切记不要使用alert()作为消息,否则您将阻止处理。改为使用弹出式div
  • 在处理开始时显示一个模式弹出框div,并显示一条消息(例如“仍在处理中,请稍候...”)或进度条或某种动画。模式弹出框阻止用户与页面进行交互,因此他们无法点击任何内容。为此,模式弹出窗口不得有关闭按钮或任何其他方式关闭它。在处理结束时,关闭模式弹出框,以便用户现在可以继续。

重要提示:您在您的评论中提到的其他答案的覆盖(这是我的最后一点类似模式弹出)不显示,直到处理结束。这是因为你的处理正在占用处理器并阻止它处理UI线程。当你可以做的是延迟你的处理。因此,首先显示模式弹出窗口(或覆盖图),然后使用setTimeout()在1秒后开始处理(也许500毫秒或更少就足够了)。这使处理器有足够的时间来处理UI线程,然后开始进行长时间处理。

编辑这里是最后的方法的一个示例:

function start() { 
 
    disableUI(); 
 
    setTimeout(function() { 
 
    process(); 
 
    }, 1000); 
 
} 
 

 
function process() { 
 
    var s = (new Date()).getTime(); 
 
    var x = {}; 
 
    for (var i = 0; i < 99999; i++) { 
 
    x["x" + i] = i * i + i; 
 
    } 
 
    var e = new Date().getTime(); 
 
    $("#results").text("Execution time: " + (e - s)); 
 
    enableUI(); 
 
} 
 

 
function disableUI() { 
 
    $("#uiOverlay").dialog({ 
 
    modal: true, 
 
    closeOnEscape: false, 
 
    dialogClass: "dialog-no-close", 
 
    }); 
 
} 
 

 
function enableUI() { 
 
    $("#uiOverlay").dialog("close"); 
 
}
.dialog-no-close .ui-dialog-titlebar { 
 
    display: none; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> 
 

 
<button type="button" onclick="start()">Start</button> 
 
<div id="results"></div> 
 
<div id="uiOverlay" style="display: none;">Processing... Please wait...</div>

编辑2这里是第三方法的一个例子:

$("#StartButton").on("click", start); 
 

 
function start() { 
 
    //remove all previous click events 
 
    $("#StartButton").off("click"); 
 
    //set the click event to show the message 
 
    $("#StartButton").on("click", showProcessingMsg); 
 
    //clear the previous results 
 
    $("#results").text(""); 
 
    setTimeout(function() { 
 
    process(); 
 
    }, 1000); 
 
} 
 

 
function process() { 
 
    var s = (new Date()).getTime(); 
 
    var x = {}; 
 
    for (var i = 0; i < 99999; i++) { 
 
    x["x" + i] = i * i + i; 
 
    } 
 
    var e = new Date().getTime(); 
 
    $("#results").text("Execution time: " + (e - s)); 
 

 
    //remove all previous click events 
 
    $("#StartButton").off("click"); 
 
    //set the click event back to original 
 
    $("#StartButton").on("click", start); 
 
} 
 

 
function showProcessingMsg() { 
 
    $("#results").text("Still processing, please wait..."); 
 
}
.dialog-no-close .ui-dialog-titlebar { 
 
    display: none; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<button type="button" id="StartButton">Start</button> 
 
<div id="results"></div>

+0

Racil,你有没有第三个解决方案的例子,你可以指点我?最后的解决方案似乎是最简单的,不管我做什么,我都无法在处理开始前显示div。 – NJA

+0

我已添加一个例子,你如何在第四种方法(UI覆盖)中做到这一点。如果你仍然是第三种方法的例子,请告诉我。 –

+0

第三种方法的例子将不胜感激。实际上让覆盖方法起作用,所以我使用的是SweetAlert2,正如你所指出的那样,它是一个警报,并且专门用于阻止UI。 – NJA

0

如果是长循环浏览器本身会阻止所有其他事件。您可能只会遇到冻结浏览器。

这不会是一个很好的经验。

您可以查看覆盖的Overlay这样的UI,并告知用户有关操作

+0

我将OpenNav()函数添加到我的代码的开头,但叠加不显示,直到*原始JavaScript完成后*。
'changeZeroDiscountButton.click(功能(事件){ openNav(); VAR值= discountComboBox.jqxComboBox( 'VAL');! 如果((值=空)&&(值= “”)){ ' – NJA