knockout.js viewmodel卡在调用WebAPI的循环中

knockout.js viewmodel卡在调用WebAPI的循环中,knockout.js,Knockout.js,我不熟悉Knockout.js,正在使用它绑定来自WebAPI调用的数据。 我遇到了一个令人沮丧的场景,在一个无限循环中调用getData()方法。调试之后,我发现当我注释掉console.log(self.activityLogs())时,它消失了。当我把它放在getData方法中时,它不会引起循环问题 有人能解释这里发生了什么,为什么会发生这种无限循环吗 $(function () { var ActivityLogViewModel = function () {

我不熟悉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);
});
$(函数(){
变量ActivityLogViewModel=函数(){
self=这个;
self.activityLogs=ko.observatarray([]);//数据
getData();
console.log(self.activityLogs());//在这里,它进入无限循环
函数getData(){
$.ajax({
键入:“获取”,
url:“/api/EnvironmentsApi/activityLogs”,
contentType:“应用程序/json;字符集=utf-8”,
数据类型:“json”,
成功:功能(数据){
控制台日志(数据);
self.activityLogs(数据);
console.log(self.activityLogs());
},
错误:函数(错误){
警报(error.status+“”+error.statusText);
}
});
}
返回{
自我:自我
}
};
应用绑定(ActivityLogViewModel);
});
不确定这是否相关,但下面是我如何在HTML表中绑定它的

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

B

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

简而言之:代替
ko.applyBindings(ActivityLogViewModel)应该执行函数调用-
ko.applyBindings(ActivityLogViewModel())。因为否则您将传递“function object”,而这不是Knockout.js希望使用的。由于某种原因,在每次
activityLogs
读取之后,它都会进行
ActivityLogViewModel
调用,因此它会触发新的Ajax调用,在Ajax调用其
success
回调之后,该过程会一次又一次地启动

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

var loopCount=0;
$(函数(){
变量ActivityLogViewModel=函数(){
console.log(“函数触发”);
self=这个;
self.activityLogs=ko.observatarray([]);//数据
getData();
console.log(self.activityLogs());//在这里,它进入无限循环
函数getData(){
如果(循环计数>10){
返回;
}
var requestPromise=$.Deferred();
requestPromise.done(函数(数据){
控制台日志(数据);
self.activityLogs(数据);
console.log(self.activityLogs());
loopCount++;
});
setTimeout(函数(){requestPromise.resolve([1,2,3]);},100);
}
返回{
自我:自我
}
};
应用绑定(ActivityLogViewModel);
});

项目

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