knockoutjs在函数执行期间更新视图

时间:2014-02-24 12:59:39

标签: knockout.js progress

这很可能是一个微不足道的问题。在我的JavaScript中,我有一个功能,可以执行很多操作,我想用进度更新视图。我有一个self.message = ko.observable(),我在函数执行期间不断更新。

这与我视图中的div元素绑定。我希望每次ko.observable更新时都会更新视图。

但是,这不会发生。它仅在函数完成执行时显示“消息”的最后一个值。

如何使用knockoutjs显示进度更新消息?

代码如下:

在js文件中

self.message = ko.observable("");

self.myfunction = function()
{
  self.message("start function");
....
  self.message("end function");
}
视图中的

<div data-bind="text: vm.message"></div>

由于 马丁

1 个答案:

答案 0 :(得分:1)

你只看到self.message的最后一个值的原因是你的长期运行的JavaScript函数可能同步执行。您的Web应用程序在单个线程中工作,因此在JavaScript执行完毕之前,UI不会更新。

从您的描述中可以看出,您的长时间运行任务已经分步完成,因为在您之间您有(尝试)更新UI的时刻。让UI有机会重绘的最简单方法是使用setTimeout,超时为1 ms。这将使UI有机会赶上。

这是一些丑陋的示例代码:

self.myfunction = function()
{
  self.message("start function");
  setTimeout(function () {
      subTask1();
      self.message("subtask1 complete");
      setTimeout(function () {
          subTask2();
          self.message("subtask2 complete");
          setTimeout(function () {
              subTask3();
              self.message("function complete");
          }, 1);
      }, 1);
  }, 1);
}

等。你明白了。您可能希望将其重构为辅助函数,甚至更好地利用promises来链接代码。重点是您需要在重载任务之间创建时间来更新UI。

编辑:在for-loop

中执行的代码

这是一些未经测试的代码,它们将批量运行一系列任务。您可以传递要在每个批次中运行的任务量。我没有测试过代码,但它应该非常准确。我已经设置了一些可在UI中使用的observable。例如,可观察的“进度”将显示一个百分比,您可以将其用于进度条。

var done = ko.observable(0),
    total = ko.observable(0),
    progress = ko.computed(function () {
        return Math.round(done() / total()) + '%';
    });
function executeBatch(tasks, amount, startAt) {
    // If startAt is not set, start at the first task
    startAt = startAt || 0;

    // Stop condition: all tasks are done
    if (tasks.length - 1 < startAt) {
        return;
    }

    // Execute the amount of tasks you want to run in 1 batch, or less if there aren't enough tasks left.
    for (var i = 0; i < Math.min(startAt + amount, tasks.length); i++) {
        doTask(tasks[i]);
    }

    // Update the UI
    done(startAt + amount);

    // Give the UI time to update, then recursively call this function to continue executing tasks
    setTimeout(function () {
        executeBatch(tasks, amount, startAt + amount);
    }, 1);
}
function executeAllTasks(tasks) {
    // Reset the observables
    done(0);
    total(tasks.length);

    // Start doing the work, 10 tasks at a time
    executeBatch(tasks, 10);
}