Estou apenas começando com Knockout.js (sempre quis experimentar, mas agora finalmente tenho uma desculpa!) - No entanto, estou tendo alguns problemas de desempenho realmente ruins ao vincular uma tabela a um conjunto relativamente pequeno de dados (cerca de 400 linhas ou mais).
No meu modelo, tenho o seguinte código:
this.projects = ko.observableArray( [] ); //Bind to empty array at startup
this.loadData = function (data) //Called when AJAX method returns
{
for(var i = 0; i < data.length; i++)
{
this.projects.push(new ResultRow(data[i])); //<-- Bottleneck!
}
};
O problema é que o for
loop acima leva cerca de 30 segundos ou mais com cerca de 400 linhas. No entanto, se eu mudar o código para:
this.loadData = function (data)
{
var testArray = []; //<-- Plain ol' Javascript array
for(var i = 0; i < data.length; i++)
{
testArray.push(new ResultRow(data[i]));
}
};
Em seguida, o for
loop é concluído em um piscar de olhos. Em outras palavras, o push
método do observableArray
objeto de Knockout é incrivelmente lento.
Aqui está o meu modelo:
<tbody data-bind="foreach: projects">
<tr>
<td data-bind="text: code"></td>
<td><a data-bind="projlink: key, text: projname"></td>
<td data-bind="text: request"></td>
<td data-bind="text: stage"></td>
<td data-bind="text: type"></td>
<td data-bind="text: launch"></td>
<td><a data-bind="mailto: ownerEmail, text: owner"></a></td>
</tr>
</tbody>
Minhas perguntas:
- É esta a maneira certa de vincular meus dados (que vêm de um método AJAX) a uma coleção observável?
- Espero
push
estar fazendo um recálculo pesado toda vez que eu chamá-lo, como talvez reconstruir objetos DOM vinculados. Existe uma maneira de atrasar esse recálculo ou talvez enviar todos os meus itens de uma vez?
Posso adicionar mais código, se necessário, mas tenho certeza de que isso é o que é relevante. Na maior parte do tempo, estava apenas seguindo os tutoriais do Knockout do site.
ATUALIZAR:
Seguindo o conselho abaixo, atualizei meu código:
this.loadData = function (data)
{
var mappedData = $.map(data, function (item) { return new ResultRow(item) });
this.projects(mappedData);
};
No entanto, this.projects()
ainda leva cerca de 10 segundos para 400 linhas. Admito que não tenho certeza de quão rápido isso seria sem o Knockout (apenas adicionando linhas por meio do DOM), mas tenho a sensação de que seria muito mais rápido do que 10 segundos.
ATUALIZAÇÃO 2:
Por outro conselho abaixo, dei uma chance ao jQuery.tmpl (que é nativamente suportado pelo KnockOut), e este mecanismo de modelagem desenhará cerca de 400 linhas em pouco mais de 3 segundos. Esta parece ser a melhor abordagem, exceto uma solução que carregue dinamicamente mais dados conforme você rola.