2016-11-14 4 views
1

私はKnockout.jsを初めて使用しており、WebAPI呼び出しからデータをバインドするために使用しています。 私は、getData()メソッドが無限ループで呼び出されていた、不満足なシナリオを持っていました。デバッグ後、私はconsole.log(self.activityLogs())をコメントアウトすると、それがなくなったことが分かりました。 getDataメソッドの中に置いておくと、ループの問題は発生しません。knockout.js viewmodelがループしてWebAPIを呼び出す

誰もがここで何が起こっているのか、なぜこの無限ループが起こったのか説明できますか?

$(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> 
+0

'ko.applyBindings(新しいActivityLogViewModel);' – haim770

+1

使用 'self.activityLogs.peek()'データを読み込みます。それ以外の場合は、依存関係を作成し、Knockoutは 'ActivityLogViewModel'関数全体を再評価し、無限ループを引き起こします。 – haim770

答えて

1

あなたのケースでコードスニペットを作成しました。私は小さな変更を加えました:それを再生中にページ上の無限ループを防ぐために変数loopCountを追加し、プロミスと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>

関連する問題