jQuery - 可以完成线程/异步吗?
Posted
技术标签:
【中文标题】jQuery - 可以完成线程/异步吗?【英文标题】:jQuery - Can threads/asynchronous be done? 【发布时间】:2014-11-22 00:16:35 【问题描述】:我目前正在使用 AJAX
和 Django
框架。
我可以将asynchronous
POST/GET 传递给Django
,并让它返回一个json
对象。
然后根据Django
传过来的结果,循环遍历数据,更新网页上的表格。
表格的 html:
<!-- Modal for Variable Search-->
<div class="modal fade" id="variableSearch" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Variable Name Search</h4>
</div>
<div class="modal-body">
<table id="variableSearchTable" class="display" cellspacing="0" >
<thead>
<tr>
<th> Variable Name </th>
</tr>
</thead>
</table>
<p>
<div class="progress">
<div class="progress-bar progress-bar-striped active" id="variableSearchProgressBar" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%">
<span class="sr-only">0% Complete</span>
</div>
</div>
</p>
<p>
<div class="row">
<div class="col-lg-10">
<button class="btn btn-default" type="button" id="addSearchVariable" >Add</button>
</div>
</div>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="variableSearchDataCloseButton" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
基本上它是一个bootstrap 3
模态,带有jQuery DataTable
,并带有一个向用户显示当前进度的进度条。
用于获取 Django 结果的 javascript:
$('#chartSearchVariable').click(function(event)
$('#chartConfigModal').modal("hide");
$('#variableSearch').modal("show");
var csrftoken = getCookie('csrftoken');
var blockname = document.getElementById('chartConfigModalBlockname').value;
$('#variableSearchProgressBar').css('width', "0%").attr('aria-valuenow', "0%");
event.preventDefault();
$.ajax(
type:"GET",
url:"ajax_retreiveVariableNames/",
timeout: 4000000,
data:
'csrfmiddlewaretoken':csrftoken,
'blockname':blockname
,
success: function(response)
if(response.status == "invalid")
$('#chartConfigModal').modal("hide");
$('#variableSearch').modal("hide");
$('#invalid').modal("show");
else
configurationVariableChart.row('').remove().draw(false);
for (i = 0 ; i < response.variables.length; i++)
configurationVariableChart.row.add(
$(
'<tr>' +
'<td>' + response.variables[i] + '</td>' +
'<tr>'
)[0]);
configurationVariableChart.draw();
$('#variableSearchProgressBar').css('width', "100%").attr('aria-valuenow', "100%");
,
failure: function(response)
$('#chartConfigModal').modal("hide");
$('#variableSearch').modal("hide");
$('#invalid').modal("show");
);
return false;
);
$('#addSearchVariable').click(function(event)
$('#variableSearch').modal("hide");
$('#chartConfigModal').modal("show");
document.getElementById('chartConfigModalVariable').value = currentVariableNameSelects;
);
$('#variableSearchDataCloseButton').click(function(event)
$('#variableSearch').modal("hide");
$('#chartConfigModal').modal("show");
);
问题在于更新表部分:
configurationVariableChart.row('').remove().draw(false);
for (i = 0 ; i < response.variables.length; i++)
configurationVariableChart.row.add(
$(
'<tr>' +
'<td>' + response.variables[i] + '</td>' +
'<tr>'
)[0]);
configurationVariableChart.draw();
$('#variableSearchProgressBar').css('width', "100%").attr('aria-valuenow', "100%");
由于 response.variables 可能超过 10k,它会冻结网络浏览器,即使它仍在绘图。
我对网页设计很陌生(不到 4 个月),但我认为这是因为它们都在同一个线程上运行。
在 Javascript 中有没有办法进行线程/异步?我进行了搜索,结果被延迟/承诺,目前看起来非常抽象。
【问题讨论】:
【参考方案1】:尝试以增量方式处理检索到的数据。
在下面的部分,以 250 个块生成的元素,主要使用 jQuery deferred.notify() 和 deferred.progress()。
当处理完所有 10,000 个项目时,deferred
对象为 resolved
,包含 10,000 个元素。然后在deferred.then() 的.done()
回调中对.html()
进行一次调用,将元素添加到document
; .fail()
回调转换为 null
。
或者,可以在 deferred.progress
回调中以 250 个块将元素附加到 document
;而不是在 deferred.done
中的单个调用,它发生在整个任务完成时。
setTimeout
用于防止“冻结网络浏览器”情况。
$(function()
// 10k items
var arr = $.map(new Array(10000), function(v, k)
return v === undefined ? k : null
);
var len = arr.length;
var dfd = new $.Deferred();
// collection of items processed at `for` loop in blocks of 250
var fragment = [];
var redraw = function()
for (i = 0 ; i < 250; i++)
// configurationVariableChart.row.add(
// $(
fragment.push('<tr>' +
'<td>' + arr[i] + '</td>' +
'</tr>')
// )[0]);
;
arr.splice(0, 250);
console.log(fragment, arr, arr.length);
return dfd.notify([arr, fragment])
;
$.when(redraw())
// `done` callbacks
.then(function(data)
$("#results").html(data.join(","));
delete fragment;
// `fail` callbacks
, null
// `progress` callbacks
, function(data)
// log , display `progress` of tasks
console.log(data);
$("progress").val(data[1].length);
$("output:first").text(Math.floor(data[1].length / 100) + "%");
$("output:last").text(data[1].length +" of "+ len + " items processed");
$("#results").html("processing data...");
if (data[0].length)
var s = setTimeout(function()
redraw()
, 100)
else
clearTimeout(s);
dfd.resolve(data[1]);
)
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<progress min="0" max="10000"></progress><output for="progress"></output>
<output for="progress"></output><br />
<table id="results"></table>
jsfiddle http://jsfiddle.net/guest271314/ess28zLh/
【讨论】:
【参考方案2】:延迟/承诺在这里对您没有帮助。浏览器中的 JS 始终是单线程的。
诀窍是不要通过 JS 构建 DOM 元素。那总是会很昂贵而且很慢。与其从 Django 以 JSON 格式传递数据并动态构建 DOM,不如让 Django 在服务器端呈现模板片段并将整个内容传递到前端,JS 可以简单地将其插入到相关点.
【讨论】:
除了这样做还有其他选择吗?因为整个页面是动态的,这意味着一些表是由 JS 创建的,然后使用 AJAX 填充。进程中没有刷新? 但这就是为什么我说渲染一个片段,而不是整个页面。每个表仍然可以是一个单独的 Ajax 调用,但服务器会返回一个您插入的 HTML 块。 @DanielRoseman 为什么要这么麻烦?为什么不直接使用现有数据并在前端生成模板并附加一次?为什么要在客户端和服务器之间混淆数据和 HTML? @DanielRoseman 我想我明白你的意思,试图在服务器端生成 HTML,然后放到客户端。我可以这样做,但我不想这样做,因为我认为数据只是服务器应该传递的。以上是关于jQuery - 可以完成线程/异步吗?的主要内容,如果未能解决你的问题,请参考以下文章
OCUnit 可以依赖后台线程中的代码吗? (为了测试异步请求)