淘汰ObservableArray异步调用绑定订单问题

时间:2016-12-10 09:32:44

标签: javascript asp.net performance knockout.js

我有一个ObservableArray。使用ajax异步调用我正在获取绑定数据。将有1000个数据。在每次通话中都会获取100个数据。问题是由于ajax异步调用顺序不会是1 - 1000.无法将其作为同步调用,因为浏览器不会响应。如何在淘汰赛中对异步数据进行排序?

var DataVM = ko.observableArray([]);
ko.applyBindings(DataVM, document.getElementById("ControlBlock"));

for (var i = 0; i < totalAjaxCall; i++) {
                        GetData(guid, start, end, self.DataCallback);
                        start = start + 100;
                        end = end +100;
                    }

 DataCallback= function (result) {
        var temp = JSON.parse(result.d); 
        var data = [];
        var data = temp.Data;
        for (var j = 0; j < data.length; j++) {
            var tempItem_ = new Item();
            tempItem_.Number = data[j].Number;
        // Other codes           
            DataVM.push(tempItem_ );
        }
    };

2 个答案:

答案 0 :(得分:1)

你可以记住它们进来时的块,然后在你收到它们时重新组装它们。见评论:

var DataVM = ko.observableArray([]);
ko.applyBindings(DataVM, document.getElementById("ControlBlock"));

// Remember the results in a temporary array of arrays
var received = 0;
var receivedBlocks = [];

for (var i = 0; i < totalAjaxCall; i++) {
    // Tell `DataCallback` which block it's going to get
    GetData(guid, start, end, self.DataCallback.bind(null, i));
    // No need for `self` ----^^^^^
    start = start + 100;
    end = end +100;
}

DataCallback = function (i, result) {
    // Create and remember the items for this block
    receivedBlocks[i] = JSON.parse(result.d).map(function(e) {
        var tempItem_ = new Item();
        tempItem_.Number = num;
        return tempItem_;
    });
    ++received;

    // Do we have them all?
    if (received == totalAjaxCall) {
        // Flatten our array of arrays, now we have all the pieces
        var receivedItems = []
        receivedBlocks.forEach(function(block) {
            receivedItems.push.apply(result, block);
        });

        // Push all of those onto DataVM as a single operation
        // Note: You were using `DataVM.push`, so I used that here,
        // but if you wanted to *replace* the contents of `DataVM`,
        // (or if you know it's empty), you'd just do:
        //      DataVM(receivedItems);
        // instead.
        DataVM.push.apply(DataVM, receivedItems);
    }
};

答案 1 :(得分:0)

我不确定您希望偏离当前代码的距离,但我想宣传一些淘汰赛的其他功能:)

如果你创建一个小的&#34;中间&#34;根据您的请求建模,您可以使用computed值自动跟踪正确排序的数据列表。

例如,如果你这样定义new Request()

var Request = function(start, end) {
  this.completed = ko.observable(false);
  this.data = [];

  getData(start, end, this.onLoad.bind(this));
};

Request.prototype.onLoad = function(data) {
  this.data = data;
  this.completed(true);
};

您可以更改for循环以创建&#34;中间&#34;楷模。这会为Request0100101创建201,等等。这些模型中的每一个都按照创建的顺序存储在数组中

function getDataRequests(start, end, chunkSize) {
  var requests = [];
  for (var i = start; i < end; i += chunkSize) {
    requests.push(new Request(i, Math.min(i + chunkSize, end)));
  }
  return requests;
};

现在您可以创建一个有序数组,您可以通过将所有data个请求合并在一起来计算另一个有序数组completed

var DataVM = function(start, end, chunkSize) {
  // We keep track of a list of requests
  var requests = ko.observableArray(
    getDataRequests(start, end, chunkSize)
  );

  // Because requests have an observable completed prop,
  // we can automatically keep track of a list of completed
  // requests
  var completedRequests = ko.pureComputed(() =>
    requests().filter(r => r.completed()));

  // Now, whenever a requests completes, we flatten the 
  // `data` parts for `completed` requests
  this.data = ko.pureComputed(() => completedRequests()
    .reduce((items, r) => items.concat(r.data), []));
};

因为您拥有requests数组,所以可以轻松计算UI属性。例如:firstLoaded是一个计算结果,它返回第一个请求的completed值。

这是一个完整的例子(ES2015):

&#13;
&#13;
var DataVM = function(start, end, chunkSize) {
  // We keep track of a list of requests
  var requests = ko.observableArray(
    getDataRequests(start, end, chunkSize)
  );

  // Because requests have an observable completed prop,
  // we can automatically keep track of a list of completed
  // requests
  var completedRequests = ko.pureComputed(() =>
                                          requests().filter(r => r.completed()));

  // Now, whenever a requests completes, we flatten the 
  // `data` parts for `completed` requests
  this.data = ko.pureComputed(() => completedRequests()
                              .reduce((items, r) => items.concat(r.data), []));

  // Shows progress
  this.loadingMsg = ko.pureComputed(() => {
    var completedCount = completedRequests().length,
      	allCount = requests().length;

    return completedCount === allCount 
    	? `Done loading ${end - start} items in ${allCount} steps` 
      : `Loading... (${completedCount}/${allCount})`;
  });

  // Check if the first (if any) request has completed loading
  this.firstCompleted = ko.pureComputed(() =>
    requests().length && requests()[0].completed());
};


var Request = function(start, end) {
  this.completed = ko.observable(false);
  this.data = [];

  getData(start, end, this.onLoad.bind(this));
};

Request.prototype.onLoad = function(data) {
  this.data = data;
  this.completed(true);
};

var vm = new DataVM(0, 50, 5);
ko.applyBindings(vm);

// Mock async ajax stuff and data getters
function getDataRequests(start, end, chunkSize) {
  var requests = [];
  for (var i = start; i < end; i += chunkSize) {
    requests.push(new Request(i, Math.min(i + chunkSize, end)));
  }
  return requests;
};

function getData(start, end, cb) {
  setTimeout(function() {
  	cb(mockData(start, end));
  }, Math.random() * 3000 + 500);
}

function mockData(from, to) {
	return Array(to - from).fill(from).map(function(_, i) {
      return from + i;
  });
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="text: loadingMsg"></div>

<ul data-bind="foreach: data, visible: firstCompleted" style="border: 1px solid black;">
  <li data-bind="text: $data"></li>
</ul>
&#13;
&#13;
&#13;