繁体   English   中英

Knockout.js映射并将大数据集添加到ko.observableArray

[英]Knockout.js Mapping and adding large dataset to ko.observableArray

有许多使用底层数组将大型数据集添加到ko.observableArray的示例,例如:

ko.observableArray.fn.pushAll = function(valuesToPush) {
var underlyingArray = this();
this.valueWillMutate();
ko.utils.arrayPushAll(underlyingArray, valuesToPush);
this.valueHasMutated();
return this;  //optional
};

用这种方式做的问题是我失去了可观察的东西。 当我使用chrome并在调试器中暂停时,我将在数组中获取值,而不是在函数c()中观察到的换行。 我还必须观察许多这些变量。

我发现有效的方法如下:

var model = @Html.Raw(Json.Encode(Model));
vm.POs = ko.mapping.fromJS(model.POs);

问题是这很慢。 如何使用基础数组进行添加,然后将可观察的换行添加到每个变量而又不存在性能问题?

这是更多代码:

var vm = {
    POs: ko.observableArray([]),

    headersWithAccounting: ko.observableArray([
        {header_name: "DATE CREATED", property: "DATE_CREATED", state: ko.observable('')},
        {header_name: "DATE ISSUED", property: "DATE_ISSUED", state: ko.observable('')},
        {header_name: "USER CREATED", property: "NAME_USER", state: ko.observable('')},
        {header_name: "PO NUMBER", property: "NO_PO", state: ko.observable('')},
        {header_name: "ORDER STATUS", property: "NAME_STATUS", state: ko.observable('')},
        {header_name: "VENDOR", property: "NAME_VENDOR", state: ko.observable('')},
        {header_name: "TOTAL COST", property: "COST_TOTAL", state: ko.observable('')},
        {header_name: "CTU", property: "ID_CTU", state: ko.observable('')},
        {header_name: "ACCOUNTING CODE", property: "ACCOUNTING_CODE_NAME", state: ko.observable('')},
        {header_name: "CLOSE ORDER", property: "ACCOUNTING", state: ko.observable('')}
    ])
};

function PO() {
var self = this;

self.ID_ORDER = ko.observable();
self.DATE_CREATED = ko.observable();
self.DATE_ISSUED = ko.observable();
self.NAME_STATUS = ko.observable();
self.NAME_VENDOR = ko.observable();
self.NAME_USER = ko.observable();
self.COST_TOTAL = ko.observable();
self.ACCOUNTING_CODE_NAME = ko.observable();
self.ACCOUNTING_CODE_ID = ko.observable();
self.NO_PO = ko.observable();
self.SHOWDETAILS = ko.observable(0);
self.ID_TYPE = ko.observable(0);
self.DESCRIPTION = ko.observable('');
self.FILES = ko.observableArray();
self.POParts = ko.observableArray();
self.ACCOUNTING = ko.observable(0);
self.ID_CTU = ko.observable(0);
self.ACCOUNTING.subscribe(function(val) {
    if (vm.avoidCloseOrder() == 0) {
        $.ajax({
            type: "POST",
            url: '@Url.Action("AccountingCloseOrder", "Report")',
            dataType: 'JSON',
            data: {
                orderId: self.ID_ORDER()
            },
            success: function(msg) {
                if (msg != 'Good') {
                    window.location.href = msg;
                }
            },
            error: function (err) {
                alert("Error closing order, please try again");
            }
        });
    }
});
self.ACCOUNTING_CODE_ID.subscribe(function(val) {
    if (vm.avoidCloseOrder() == 0) {
        $.ajax({
            type: "POST",
            url: '@Url.Action("AccountingCodeChange", "Report")',
            dataType: 'JSON',
            data: {
                orderId: self.ID_ORDER(),
                accountingCodeId: self.ACCOUNTING_CODE_ID()
            },
            success: function(msg) {
            },
            error: function (err) {
                alert("Error closing order, please try again");
            }
        });
     }
  });
}

function POPart() {
    var self = this;

    self.CATEGORY = ko.observable();
    self.SUBCATEGORY = ko.observable();
    self.DESCRIPTION = ko.observable();
    self.PARTNO = ko.observable();
    self.QTY_ORDERED = ko.observable();
    self.QTY_RECEIVED = ko.observable();
    self.COST = ko.observable();
}

function FILE() {
    var self = this;

    self.LOCATION = ko.observable();
}

现在问题出在带有剔除绑定的剃须刀代码中:

<div class="row">
    <div class="col-md-12">
        <div data-bind="foreach:POs">
            <table class="table-responsive">
                <thead data-bind="if: $index() == 0 || ($index() > 0 && vm.POs()[$index()-1].SHOWDETAILS() == 1)">
                    <tr data-bind="foreach:vm.headersWithAccounting">
                        <th>
                            <span data-bind="click:$root.sortPOs.bind(property), text:header_name" style="cursor:pointer"></span><i data-bind="css: state"></i>
                        </th>
                    </tr>
                </thead>
                <tbody class="clickabletbody">
                    <tr>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:DATE_CREATED"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:DATE_ISSUED"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_USER"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NO_PO"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_STATUS"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_VENDOR"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:COST_TOTAL"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:ID_CTU"></div>
                        </td>
                        <td>
                            @Html.DropDownList("ddlVendor", new SelectList(Model.ACCOUNTING_CODE_SELECTLIST, "Value", "Text"), "--Select Accounting Code--", new { @class = "form-control", data_bind = "value:ACCOUNTING_CODE_ID" })
                        </td>
                        <td>
                            <input type="checkbox" style="height:30px; width: 30px;" data-bind="checked:ACCOUNTING, enable:(NAME_STATUS() == 'ACCOUNTING' || NAME_STATUS() == 'CLOSED')" />  //PROBLEM RIGHT HERE!!!!
                        </td>
                    </tr>
                </tbody>
            </table>
            <table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
                <!-- ko if:(ID_TYPE() == 2 || ID_TYPE() == 3) -->
                <thead>
                    <tr>
                        <th>
                            DESCRIPTION
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>
                            <div data-bind="text:DESCRIPTION"></div>
                        </td>
                    </tr>
                </tbody>
                <!-- /ko -->
                <!-- ko if:(ID_TYPE() == 1) -->
                <thead>
                    <tr>
                        <th>
                            CATEGORY
                        </th>
                        <th>
                            SUBCATEGORY
                        </th>
                        <th>
                            DESCRIPTION
                        </th>
                        <th>
                            PART NO
                        </th>
                        <th>
                            QTY ORDERED
                        </th>
                        <th>
                            QTY RECEIVED
                        </th>
                        <th>
                            COST
                        </th>
                    </tr>
                </thead>
                <tbody data-bind="foreach:POParts">
                    <tr>
                        <td>
                            <div data-bind="text:CATEGORY"></div>
                        </td>
                        <td>
                            <div data-bind="text:SUBCATEGORY"></div>
                        </td>
                        <td>
                            <div data-bind="text:DESCRIPTION"></div>
                        </td>
                        <td>
                            <div data-bind="text:PARTNO"></div>
                        </td>
                        <td>
                            <div data-bind="text:QTY_ORDERED"></div>
                        </td>
                        <td>
                            <div data-bind="text:QTY_RECEIVED"></div>
                        </td>
                        <td>
                            <div data-bind="text:COST"></div>
                        </td>
                    </tr>
                </tbody>
                <!-- /ko -->
            </table>
            <table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
                <thead>
                    <tr>
                        <th>
                            Files
                        </th>
                    </tr>
                </thead>
                <tbody data-bind="foreach:FILES">
                    <tr>
                        <td>
                            <a data-bind="attr: {href: LOCATION, target: '_blank'}" class="btn btn-primary btn-md">Download File</a>
                        </td>
                    </tr>
                </tbody>
            </table>
            <div data-bind="if:SHOWDETAILS"><hr /></div>
        </div>
        <!-- /ko -->
    </div>
</div>

问题出在复选框上,Chrome控制台显示错误:knockout-3.4.0.js:72未捕获的TypeError:无法处理绑定“启用:function(){返回(NAME_STATUS()=='ACCOUNTING'|| NAME_STATUS() =='CLOSED')}“消息:NAME_STATUS不是函数

这是因为在该值中,它不再是具有剔除绑定的函数,它只是一个值,因此,它不是函数,并且此错误是正确的。 我迷路了,因为使用基础数组仅推送javascript值,并且未映射可观察的函数。

当前使用可观察对象映射200个条目大约需要10秒钟,如果您问我,这是非常荒谬的。 当我有1000+时会发生什么。 即使我只加载其中的50个并使用ajax收集其余信息,但每次获得更多数据时,它都会滞后页面几秒钟,直到全部加载。 不确定如何解决此问题。

编辑:

我刚好有一个AHA时刻,并解决了丢失绑定问题。 现在大约需要4秒来处理232个条目。 仍然想更快地获得它,但是这就是我所做的改变。

function PO(data) {
    var self = this;

    self.ID_ORDER = ko.observable(data.ID_ORDER);
    self.DATE_CREATED = ko.observable(data.DATE_CREATED);
    self.DATE_ISSUED = ko.observable(data.DATE_ISSUED);
    self.NAME_STATUS = ko.observable(data.NAME_STATUS);
    self.NAME_VENDOR = ko.observable(data.NAME_VENDOR);
    self.NAME_USER = ko.observable(data.NAME_USER);
    self.COST_TOTAL = ko.observable(data.COST_TOTAL);
    self.ACCOUNTING_CODE_NAME = ko.observable(data.ACCOUNTING_CODE_NAME);
    self.ACCOUNTING_CODE_ID = ko.observable(data.ACCOUNTING_CODE_ID);
    self.NO_PO = ko.observable(data.NO_PO);
    self.SHOWDETAILS = ko.observable(0);
    self.ID_TYPE = ko.observable(data.ID_TYPE);
    self.DESCRIPTION = ko.observable(data.DESCRIPTION);

    self.FILES = ko.observableArray();

    if (data.FILES != null) {
        for (var i = 0; i < data.FILES.length; i++) {
            self.FILES.push(new FILE(data.FILES[i]));
        }
    }

    self.POParts = ko.observableArray();

    if (data.POParts != null) {
        for (var i = 0; i < data.POParts.length; i++) {
            self.POParts.push(new POPart(data.POParts[i]));
        }
    }

    self.ACCOUNTING = ko.observable(data.ACCOUNTING);

    self.ID_CTU = ko.observable(data.ID_CTU);

    self.ACCOUNTING.subscribe(function(val) {
        if (vm.avoidCloseOrder() == 0) {
            $.ajax({
                type: "POST",
                url: '@Url.Action("AccountingCloseOrder", "Report")',
                dataType: 'JSON',
                data: {
                    orderId: self.ID_ORDER()
                },
                success: function(msg) {
                    if (msg != 'Good') {
                        window.location.href = msg;
                    }
                },
                error: function (err) {
                    alert("Error closing order, please try again");
                }
            });
        }
    });

    self.ACCOUNTING_CODE_ID.subscribe(function(val) {
        if (vm.avoidCloseOrder() == 0) {
            $.ajax({
                type: "POST",
                url: '@Url.Action("AccountingCodeChange", "Report")',
                dataType: 'JSON',
                data: {
                    orderId: self.ID_ORDER(),
                    accountingCodeId: self.ACCOUNTING_CODE_ID()
                },
                success: function(msg) {
                },
                error: function (err) {
                    alert("Error closing order, please try again");
                }
            });
        }
    });
}

function POPart(data) {
    var self = this;

    self.CATEGORY = ko.observable(data.CATEGORY);
    self.SUBCATEGORY = ko.observable(data.SUBCATEGORY);
    self.DESCRIPTION = ko.observable(data.DESCRIPTION);
    self.PARTNO = ko.observable(data.PARTNO);
    self.QTY_ORDERED = ko.observable(data.QTY_ORDERED);
    self.QTY_RECEIVED = ko.observable(data.QTY_RECEIVED);
    self.COST = ko.observable(data.COST);
}

function FILE(data) {
    var self = this;

    self.LOCATION = ko.observable(data.LOCATION);
}

和推送功能:

ko.observableArray.fn.pushAll = function(valuesToPush)
{
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayForEach(valuesToPush, function(item) {
        underlyingArray.push(new PO(item));
    });
    this.valueHasMutated();
    return this;
}

有什么想法可以使速度快于4秒吗?

我没有真正理解“我松开约束”的意思。 这可能是调试器的伪像(它向您显示了可观察的值)。

我也可能是“这个”问题。

我得到了有效的代码段(在填充数组时可以使用单击绑定)

 var elementVM = (function () { function elementVM(message) { this.myText = ko.observable(message); } elementVM.prototype.changeText = function () { this.myText(this.myText() + " changed"); }; return elementVM; }()); var myVM = (function() { var getText = function(count) { return "My Text " + (count); }; var myObservableArray = ko.observableArray([new elementVM(getText(0))]); return function() { this.myArray = myObservableArray; myVM.prototype.populate = function() { myObservableArray.valueWillMutate(); for(var i = 1; i <= 1000; ++i) { myObservableArray().push(new elementVM("My Text " + i)); } myObservableArray.valueHasMutated(); }; }; }()); var vm = new myVM(); ko.applyBindings(vm); setTimeout(function() { var start = new Date(); vm.populate(); var stop = new Date(); document.getElementById("pushAll").innerHTML = "pushallTiming: " + (stop - start); }, 1000); 
 li { list-style: none; border: 1px solid black; width: auto; text-align: center; } #pushAll { background-color: red; width: auto; text-align: center; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <div id="pushAll"></div> <ul data-bind="template: { name: 'my-template', foreach: myArray }"></ul> <script type="text/html" id="my-template"> <li data-bind="text: myText, click: changeText"></li> </script> 

实际复制到阵列所需的时间少于1秒。 它是valueHasMutated()函数,需要花费几秒钟,而多数民众赞成在这只是KO的一部分。 我很高兴它花了很长时间将数据复制到数组中。 我将尝试仅对50个条目进行分页,这应有助于DOM更快地加载。 谢谢大家的回应。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM