【问题标题】:jQuery - Can threads/asynchronous be done?jQuery - 可以完成线程/异步吗?
【发布时间】:2018-04-07 21:18:07
【问题描述】:

我目前正在使用 AJAXDjango 框架。

我可以将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">&times;</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" width="100%">
                <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 中有没有办法进行线程/异步?我进行了搜索,结果被延迟/承诺,目前看起来非常抽象。

【问题讨论】:

    标签: javascript jquery django asynchronous


    【解决方案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,然后放到客户端。我可以这样做,但我不想这样做,因为我认为数据只是服务器应该传递的。
      猜你喜欢
      • 2021-10-03
      • 1970-01-01
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多