2012-09-25 3 views
0

관찰 가능 항목이 다소 많은 KnockoutJS를 사용하는 페이지가 있습니다 (약 35 개가 여기 관련되고 일부는 60 개입니다). KO 매핑 플러그인을 사용하지만 문제가 있는지 여부는 알 수 없습니다.KnockoutJS : 관측 가능 횟수가 많은 스퓨리어스 콜백

관찰 가능 항목의 대부분 (전부는 아님)이 입력 필드에 바인딩됩니다.

사용자는 현재 입력 집합을 명명 된 집합에 저장하거나 이전에 저장된 집합에서 다시로드 할 수 있습니다. 현재 입력 집합이 저장된 집합에서 왔는지 또는 편집 된 (저장되지 않은) 입력인지 여부를 나타내는 UI가 있습니다.

입력을 편집 할 때 "저장 /로드 입력"UI를 업데이트하기 위해 (어느 것이 든 상관 없습니다) 모든 관련 '입력'관측 자료를 구독합니다.

여기 내 기괴한 문제가 있습니다. 구독 된 관찰 가능 횟수가 약 25 이상인 경우 ko.applyBindings(...) 콜의 깊은 곳에서 내 콜백 함수에 대한 가짜 호출이 발생합니다. 이 발생하면

  • 보고됩니다 입력은 일반적으로 내가에 가입 마지막 하나만 가짜 콜백이있다.
  • 구독을 충분히 제거하여 약 25 개 이하로 구독하면 가짜 콜백이 사라집니다.
  • 내가 그 한도를 지키고 구독을 계속 추가하면 목록에 계속 추가됨에 따라 다른 필드에 대한 통화가 다시 나타납니다.
  • 모든 입력을 구독하는 경우 콜백은 __ko_mapping__에 대한 콜백으로 불합리한 것이라고 주장합니다.

구독에 올바르게 바인딩되어 있지 않거나 가입 목록이 엉망이되는 KO 또는 KO 매핑 플러그인 내에 버그가 있다고 가정해야합니다. 지금까지 문제를 추적 할 수 없었습니다.

은 가입 코드는 다음과 거의 같습니다

// markSavedInputsDirty(name) defined elsewhere 
function registerCallbacks() { 
    var data = viewModel.inputs; 
    var member; 
    for(member in data) { 
     if (data.hasOwnProperty(member) && ko.isObservable(data[member])) { 
      if(member /* ... not certain observables which I need to ignore */) { 
       data[member].subscribe(function() {return markSavedInputsDirty(member)}, data[member]); 
      } 
     } 
    } 
} 

(참고 :. 어떤 멤버 트랙 위의 코드 만 디버깅 지원으로, 호출되고 우리가 원래 문제 작물을 보았을 때, 코드를 모든 관측 대상에 대해 동일한 콜백 함수 (currying 없음)를 사용하는 데에만 사용됩니다.

이전에는 아무 것도 보지 못했습니까?

+1

콜백 함수에서 'member'는 정확하지 않습니다. 이전에 문제가 있다고 말했지 만, 실제로 디버깅하고 싶다면 올바른지 확인해야합니다. 그렇게하려면 각 구독에 대한 새 마감 장치에 저장해야합니다. 'function (member) {data [member] .subscribe (...)} (member)' –

+0

@MichaelBest, 당신 말이 맞아요. 그 폐쇄는 엉망이되어 나를 잘못 이끌었습니다. 나는 그 결의안을 간략히 업데이트 할 것이다. 감사! –

+0

알아 낸 것이 기쁩니다. 답변을 추가하고 승인 된 것으로 표시하면 좋을 것입니다. 그래야 답변이 "답이 없음"으로 남지 않습니다. 또한 내 의견에 +1을 주시면 감사하겠습니다. :-) –

답변

0

해결 방법 : @MichaelBest이 코멘트에 표시된대로

subscribe(...) 통화 폐쇄가 엉망이되었다. 비록 호출의 시점에서 member의 값을 포함 할지라도 member (모든 호출에 대해 동일한 객체)을 포함합니다. 내가 본 것은 루프의 최종 값이 member인데, 그것은 나를 잘못 이끌었습니다. 나는 자정에 이렇게해서는 안된다.내가 올바른 진단을 한 후

data[member].subscribe(markSavedInputsDirty.bind(data[member], member)); 

이 모든 것이 분명 해졌다 :

다음은 그 라인의 올바른 구현의 스퓨리어스 호출은 페이지에서 <select> 요소에 바인딩 value에서 온다. 녹아웃은 내부적으로 선택한 <option>의 값이 정확히 viewModel의 값과 일치하는지 확인해야합니다 (녹아웃 소스의 ensureDropdownSelectionIsConsistentWithModelValue(...) 참조).

필자의 경우 관찰 가능 값은 3 (숫자)이고 선택된 숫자는 자연스럽게 "3"(문자열) 인 반면 <option>입니다. 따라서 Knockout은 viewModel을 옵션의 값으로 설정하고 알림을 트리거했습니다.

따라서 원래의 구독 (내 부주의 시도)이 정확하고 알림이 합법적이었습니다. 방금 바인딩 할 때까지 내 모니터링 코드가 아무런 영향을 미치지 않도록 주변에 물건을 교환해야합니다.