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

时间:2016-11-14 21:50:50

标签: knockout.js

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

任何人都可以解释这里发生了什么以及为什么会发生这种无限循环?

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

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

if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
    // Activity was brought to front and not created,
    // Thus finishing this will get us to the last viewed activity
    finish();
    return;
}


// Regular activity creation code... }

1 个答案:

答案 0 :(得分:1)

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

简而言之:您应该执行函数调用 - ko.applyBindings(ActivityLogViewModel);,而不是ko.applyBindings(ActivityLogViewModel());。因为否则你会传递&#34;功能对象&#34;这不是Knockout.js期望使用的。由于某种原因,在每次activityLogs读取之后,它会调用ActivityLogViewModel并因此触发新的Ajax调用,之后Ajax调用其success回调并且该过程一次又一次地启动。 / p>

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

&#13;
&#13;
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);
});
&#13;
<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>
&#13;
&#13;
&#13;