【问题标题】:knockout.js viewmodel stuck in loop calling WebAPIknockout.js 视图模型陷入循环调用 WebAPI
【发布时间】:2016-11-15 06:31:54
【问题描述】:

我是 Knockout.js 的新手,我正在使用它来绑定来自 WebAPI 调用的数据。 我有一个令人沮丧的场景,getData() 方法在无限循环中被调用。调试后发现注释掉console.log(self.activityLogs())就消失了。当我将它留在 getData 方法中时,它不会导致循环问题。

谁能解释这里发生了什么以及为什么会发生这种无限循环?

$(function () {
    var ActivityLogViewModel = function () {
        self = this;
        self.activityLogs = ko.observableArray([]); //data
        getData();
        console.log(self.activityLogs());  // when this is here, it goes into infinite loop

        function getData() {
            $.ajax({
                type: "GET",
                url: "/api/EnvironmentsApi/activityLogs",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    console.log(data);
                    self.activityLogs(data);
                    console.log(self.activityLogs());
                },
                error: function (error) {
                    alert(error.status + "<--and--> " + error.statusText);
                }
            });
        }

        return {
            self: self
        }
    };
    ko.applyBindings(ActivityLogViewModel);
});

不确定这是否相关,但这是我在 HTML 表中绑定它的方式。

    <tbody data-bind="foreach: activityLogs">
        <tr>
            <td>b...</td>
        </tr>
    </tbody>

【问题讨论】:

  • ko.applyBindings(new ActivityLogViewModel);
  • 使用self.activityLogs.peek() 读取数据。否则,您将创建一个依赖项,并且 Knockout 将重新评估整个 ActivityLogViewModel 函数,从而导致无限循环。

标签: knockout.js


【解决方案1】:

我已经为您的案例创建了代码 sn-p。我做了一些小改动:添加了loopCount 变量以防止在玩页面时出现无限循环,并用 Promise 替换了 Ajax 调用(但从技术上讲,它们的行为相同)。

简而言之:你应该调用函数而不是 ko.applyBindings(ActivityLogViewModel); - ko.applyBindings(ActivityLogViewModel());。因为否则您将传递“函数对象”,而这不是 Knockout.js 期望使用的。由于某种原因,在每次读取activityLogs 之后,它都会调用ActivityLogViewModel,因此它会触发新的Ajax 调用,之后Ajax 会调用它的success 回调,并且该过程会一次又一次地开始。

实际上,为什么 Knockout 以这种方式工作是一个很好的问题(我们需要深入研究它的源代码),但至少现在我们知道如何防止无限循环问题。

var loopCount = 0;

$(function () {
    var ActivityLogViewModel = function () {
        console.log('function triggered');
      
        self = this;
        self.activityLogs = ko.observableArray([]); //data 
        getData();
        console.log(self.activityLogs());  // when this is here, it goes into infinite loop

        function getData() {
            if (loopCount > 10) {
              return;
            }
          
            var requestPromise = $.Deferred();

            requestPromise.done(function(data) {
                console.log(data);
                self.activityLogs(data);
                console.log(self.activityLogs());
              
                loopCount++;
            });

            setTimeout(function() { requestPromise.resolve([1, 2, 3]); }, 100);
        }

        return {
            self: self
        }
    };

    ko.applyBindings(ActivityLogViewModel);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<tbody data-bind="foreach: activityLogs">
        <tr>
            <td>Item</td>
        </tr>
</tbody>

【讨论】:

    猜你喜欢
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 2014-01-03
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多