Javascript 防止长时间计算时浏览器冻结和崩溃
我需要签入重复的数据库名称,并更改此名称以避免重复。我正在使用@JefréN建议的脚本Javascript 防止长时间计算时浏览器冻结和崩溃,javascript,freeze,web-worker,Javascript,Freeze,Web Worker,我需要签入重复的数据库名称,并更改此名称以避免重复。我正在使用@JefréN建议的脚本 function eliminateDuplicates() { var repeats = {}; var error = false; //cache inputs var $inputs = $("input[type='text']"); //loop through inputs and update repeats for (i = 0; i
function eliminateDuplicates() {
var repeats = {};
var error = false;
//cache inputs
var $inputs = $("input[type='text']");
//loop through inputs and update repeats
for (i = 0; i < $inputs.length; ++i) {
//cache current element
var cur = $inputs[i];
//remove class
$(cur).removeClass("double-error");
//get text of this element
var text = $(cur).val();
//no text -- continue
if (text === "") {
continue;
}
//first time we've came across this value -- intialize it's counter to 1
if ((text in repeats) === false) {
repeats[text] = 1;
}
//repeat offender. Increment its counter.
else {
repeats[text] = repeats[text] + 1;
}
//update the the value for this one
$(cur).val(text + "-" + repeats[text]);
}
return error; // always returns false since I'm not sure
// when it's supposed to return true.
}
没有成功。Chrome冻结,IE11浏览器,Firefox崩溃。怎么了?
我的记录显示在HTML表中
有些人建议使用网络工作者。也许这里有人有这种做法,并有一个运行示例?这里有一个解决方案,使用OODK-JS通过webworkers计算1.000.000个条目数组的总和
此解决方案使用SimuleDealQueoundFoundation类实现生产者/消费者设计模式:生产者(主线程)为数组的每个块生成任务并将其添加到队列中。使用者(webworker)接受队列中的任务并执行它,直到无人离开。执行所有任务后,生产者将显示最终结果
// main.js (producer)
OODK.config({
'path': {
'oodk': '../src',
'workspace': 'workspace'
}
});
OODK(function($, _){
$.import('{oodk}/foundation/utility/Thread', '[util.concurrent]', '{workspace}/project/Task');
// array helper class to handle arrays
var ArrayHelper = $.class(function($, µ, _){
$.static(function($, µ, _){
// slice an array into chunks using chunkLength argument
// as delimiter
$.public(function slice(arr, chunkLength){
return arr.reduce(function(arr, val, index){
var chunkIndex = Math.floor(index/chunkLength);
if(!arr[chunkIndex]) {
arr[chunkIndex] = [];
}
arr[chunkIndex].push(val);
return arr;
}, []);
});
// generate an array of len argument length
// containing random values
$.public(function random(len){
var arr = [];
for(var i =0; i<len; i++){
arr.push(Math.random()*10);
}
return arr;
})
});
});
// class to handle a pool of thread
var ThreadPool = $.class(function($, µ, _){
// number of threads to instantiate
$.private('num');
// queue to works with
$.private('queue');
$.public(function __initialize(num, queue){
_.num = num;
_.queue = queue;
});
// start the pool
$.public(function start(){
// bind listeners
var threadListener= $.new(Producer);
for(var i=0; i<_.num; i++){
// instantiate consumers
var consumer = $.new(OODK.foundation.util.Thread, "consumer.js");
$.on(consumer, 'thread.ready', threadListener);
consumer.start();
}
$.on(_.queue, 'synchronizedQueue.taskDone', threadListener);
});
});
// Event Listener for the thread
var Producer = $.implements(OODK.foundation.EventListener).class(function($, µ, _){
// number of task done
$.private('taskDone', 0);
// final result
$.private('finalResult', 0);
$.private(function __processEvent(evt){
if(evt.getType() === 'thread.ready'){
// the thread is ready, synchronize the queue with the current thread
queue.synchronize(evt.getTarget());
}else if(evt.getType() == 'synchronizedQueue.taskDone'){
//message received from the consumer that it has performed a task
_.taskDone++;
var cqueue = evt.getTarget();
var chunkResult = evt.getData();
_.finalResult += chunkResult;
jQuery('#chunksDone').text(_.taskDone);
if(cqueue.getCapacity() == _.taskDone){
// once all tasks are performed display the final result
$.log('final sum is ' + _.finalResult);
}else{
// each time a chunk is calculated display the intermediate result
$.log('intermediate result ' + _.finalResult);
}
}
});
});
// generate a large array of 1.000.000 random values
var myHugeArray = ArrayHelper.self.random(1000000);
// split this array into chunks of 2500 length
var chunks = ArrayHelper.self.slice(myHugeArray, 25000);
// instantiate a synchronized queue setted as size the number of chunks
var queue = $.new(OODK.foundation.util.concurrent.SynchronizedQueue, chunks.length);
// for each chunk create a task and add it to queue
for(var i=0; i<chunks.length; i++){
var chunk = chunks[i];
// create a task for each chunk of the array
var task = OODK.project.Task.self.factory(chunk);
// and add it to the queue
queue.put(task);
}
// instantiate a pool of 2 threads working on the given queue
var threadPool = $.new(ThreadPool, 2, queue);
// start the pool
threadPool.start();
$.log('calculate the sum of an array of 1.000.000 entries using 2 threads ...');
});
用于实现自定义逻辑的任务类
OODK('project', function($, _){
$.public().implements(OODK.foundation.Serializable).class(function Task($, µ, _){
// the array chunk to calculate
$.private('chunk');
$.public(function __initialize(chunk){
_.chunk = chunk;
});
// calculate the sum of all entries of a chunk
// implements the custom logic here
$.public(function execute(){
var result = 0;
for(var i=0; i<_.chunk.length; i++){
result += _.chunk[i];
}
return result;
});
$.static(function($, µ, _){
$.public(function factory(chunk){
var task = $.new($.ns.Task, chunk);
return task;
});
});
});
});
OODK('project',函数($,){
实现(OODK.Frime.SerialItaby.)类(函数任务($,^,)){
//要计算的数组块
$.private('chunk');
$.public(函数u_初始化(块){
_.chunk=chunk;
});
//计算块中所有项的总和
//在这里实现自定义逻辑
$.public(函数执行(){
var结果=0;
对于(var i=0;i我认为代码中最麻烦的部分是DOM访问:获取输入值并更新它们
根据,webworkers有其局限性,其中之一就是DOM操作。所以我放弃了这个选项
为了解决问题,我会做如下工作:
改进消除重复的算法(使其更快)
使eliminatedReplicates
asynchronous:将元素集划分为较小的元素,并在不同的事件循环勾选(setTimeout)中执行每个计算
在这里,我给你们介绍一个我想出的解决方案。希望它能给你们一些想法,帮助你们解决你们的问题
首先,我调整了一点消除了重复项
(我称之为modifyDOM
)
最后,为了测试一切,一个在DOM就绪时执行并创建10000个输入的函数,然后输出运行上述任何方法所需的时间
$(function () {
var inputsDiv = $('#inputs'), i, time;
for (i = 0; i < 10000; i++) {
var val = i % 3 === 0 ? 'Mickey' : (i % 3 === 1 ? 'Mouse' : '');
inputsDiv.append('<input type="text" class="double-error" name="FirstName" value="' + val + '">');
}
time = Date.now();
//parseElementsBlocking($("input[type='text']"));
parseElementsNonBlocking($("input[type='text']"), 100);
console.log(Date.now() - time);
});
$(函数(){
var inputsDiv=$('输入'),i,时间;
对于(i=0;i<10000;i++){
var val=i%3==0?'Mickey':(i%3==1?'Mouse':'');
输入iv.追加(“”);
}
时间=日期。现在();
//parseElementsBlocking($(“输入[type='text']”);
ParseElementsNonblock($(“输入[type='text']),100);
console.log(Date.now()-time);
});
您可以在这里测试所有内容。setTImeout
可以,您的问题是什么?您尝试过吗?发布您尝试过的内容,最好是在jsfiddle.net上,并发布一个链接。使用webworkers Ok谢谢您的建议。更新的用户尝试过这个。也许有些人有很好的工作示例?问候@KęstutisBanišauskas!我有几个问题。1。为什么需要在客户端执行此操作?2.您是否仍在访问
s中的值?如果没有,您将如何循环使用所需的值?@JefréN。谢谢,当页面从数据库中提交所有数据时。所有数据都将放入输入字段,以便进一步检查重复项并使用脚本添加数字。所以,当记录达到100条时,一切正常。当记录达到数千条时,浏览器会冻结。并弹出警报。因此,我需要一些解决方案来防止这种情况。我想也许webworker可以提供帮助,但在这里没有经验。并且需要添加一些加载栏,以了解backgrond进程正在运行。您好,感谢您的回答。似乎我遗漏了一些我可以让它工作。这个函数“function modifyDOM(elements,repeats)”对我不起作用。
//consumer.js
OODK.config({
'path': {
'oodk': '../src',
'workspace': 'workspace'
}
});
OODK(function($, _){
// import the concurrent API package as well as the task class
$.import('[util.concurrent]', '{workspace}/project/Task');
// start the synchronizer
OODK.foundation.util.concurrent.SynchronizedObject.self.start();
// EventListener Class to handle synchronized queue events
$.implements(OODK.foundation.EventListener).class(function Consumer($, µ, _){
$.protected(function __processEvent(evt){
if(evt.getType() == 'synchronizedQueue.ready'){
//queue is synchronized
var queue = evt.getTarget();
// bind listener
$.on(queue, 'synchronizedQueue.elementRetrieved', this);
// take a task: get the heap of the stack and delete it
queue.take();
}else if(evt.getType() == 'synchronizedQueue.elementRetrieved'){
// task is retrieved from the queue
var task = evt.getData();
var queue = evt.getTarget();
// execute the task
var result = task.execute();
// notify the producer that the task is done
queue.notify('synchronizedQueue.taskDone', result);
if(queue.remainingElements()>0){
// at least one task is still in the queue, take it
queue.take();
}
}
});
});
var threadListener = $.new(_.Consumer);
// global listener for the synchronizedQueue.ready event
// triggered when the synchronzied queue is synchronized with this thread
$.on('synchronizedQueue.ready', threadListener);
});
OODK('project', function($, _){
$.public().implements(OODK.foundation.Serializable).class(function Task($, µ, _){
// the array chunk to calculate
$.private('chunk');
$.public(function __initialize(chunk){
_.chunk = chunk;
});
// calculate the sum of all entries of a chunk
// implements the custom logic here
$.public(function execute(){
var result = 0;
for(var i=0; i<_.chunk.length; i++){
result += _.chunk[i];
}
return result;
});
$.static(function($, µ, _){
$.public(function factory(chunk){
var task = $.new($.ns.Task, chunk);
return task;
});
});
});
});
function modifyDOM(elements, repeats) {
var input, text, i = 0;
for (; i < elements.length; i++) {
input = elements[i];
text = input.value;
// Remove class.
input.className = input.className.replace(/\bdouble-error\b/, '');
if (text) {
repeats[text] = ~~repeats[text] + 1;
input.value = text + "-" + repeats[text];
}
}
}
function parseElementsNonBlocking(elements, maxChunkSize) {
var repeats = {},
nChunks = Math.floor(elements/maxChunkSize),
i = 0,
j = 1;
//loop through inputs and update repeats
for(; i < nChunks; i++, j++) {
setTimeout(modifyDOM.bind(null, elements.slice(i, j*maxChunkSize), repeats), 0);
}
// Rest
setTimeout(modifyDOM.bind(null, elements.slice(i), repeats), 0);
}
function parseElementsBlocking(elements) {
var repeats = {};
//loop through inputs and update repeats
modifyDOM(elements, repeats);
}
$(function () {
var inputsDiv = $('#inputs'), i, time;
for (i = 0; i < 10000; i++) {
var val = i % 3 === 0 ? 'Mickey' : (i % 3 === 1 ? 'Mouse' : '');
inputsDiv.append('<input type="text" class="double-error" name="FirstName" value="' + val + '">');
}
time = Date.now();
//parseElementsBlocking($("input[type='text']"));
parseElementsNonBlocking($("input[type='text']"), 100);
console.log(Date.now() - time);
});