Comprendo che l'associazione dei dati bidirezionale può essere costosa e lenta. Ad esempio, immagina un'app della lista della spesa che ti consente di elencare gli articoli della spesa e i loro prezzi e ti mostra la somma dei prezzi ( CodePen ).
HTML
<div ng-app="app">
<div ng-controller="MainCtrl">
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{ item.name }}</td>
<td>
<input type="number" ng-model="item.price">
</td>
</tr>
</tbody>
</table>
<p>Total: {{ getTotal() }}</p>
</div>
</div>
JS
angular
.module('app', [])
.controller('MainCtrl', function ($scope) {
$scope.items = [{
name: 'Milk',
price: 3.00,
}, {
name: 'Eggs',
price: 2.50
}, {
name: 'Bread',
price: 2.00
}];
$scope.getTotal = function () {
let total = 0;
$scope.items.forEach(function (item) {
total += item.price
});
return total;
};
})
;
Immagina che l'utente digiti nel campo di inserimento del prezzo del latte. In un mondo perfetto, Angular saprebbe assicurarsi che il campo di input del latte rifletta il nuovo valore e aggiorni il totale. Ma in realtà, Angular non sa che quelle sono le uniche cose da aggiornare. Cosa succede se ho un campo "latte + costo del pane"? Poi quel campo avrebbe bisogno di essere aggiornato anche.
Quindi Angular passa attraverso tutti delle proprietà del modello che vengono visualizzate nella vista e chiede "Sei cambiato? Se è così, ti rosterò". Se questa lista è lunga, ovviamente ci vorrà molto tempo.
Ma in qualcosa come React o Vue, la mia impressione è che dovrebbe richiedere un tempo ugualmente lungo. Ecco un'implementazione della stessa app giocattolo in Vue ( CodePen ):
HTML
<div id="app">
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items">
<td>{{ item.name }}</td>
<td>
<input
type="number"
v-bind:value="item.price"
v-on:change="setItemPrice(item, $event)"
>
</td>
</tr>
</tbody>
</table>
<p>Total: {{ total }}</p>
</div>
JS
new Vue({
el: '#app',
computed: {
total: function () {
let total = 0;
this.items.forEach(function (item) {
total += item.price;
});
return total;
},
},
data: {
items: [{
name: 'Milk',
price: 3.00,
}, {
name: 'Eggs',
price: 2.50
}, {
name: 'Bread',
price: 2.00
}],
},
methods: {
setItemPrice: function (item, event) {
item.price = Number(event.target.value);
},
},
});
La mia comprensione è che dopo che l'evento change è stato attivato e che il metodo del gestore ( setItemPrice
) ha terminato l'esecuzione, Vue calcolerà un nuovo DOM virtuale, differendolo con il DOM virtuale precedente, individuando il set minimo di mutazioni DOM da eseguire e quindi eseguirli.
Penso che il processo di attraversamento del DOM e vedere se ci sono delle differenze richiederebbe almeno il tempo necessario per attraversare l'array degli osservatori durante il controllo sporco. La mia impressione è che ci vorrebbe più tempo. Guarda l'HTML:
<table>
<thead>...</thead>
<tbody>
<tr>
<td>Milk</td>
<td>3</td>
</tr>
<tr>
<td>Bread</td>
<td>2.5</td>
</tr>
<tr>
<td>Eggs</td>
<td>2</td>
</tr>
</tbody>
</table>
<p>Total: 7.5</p>
Se n
= la dimensione della lista della spesa, la verifica sporca deve scorrere attraverso n
elementi nella matrice degli osservatori. Ma nel percorrere il DOM, devi scorrere i n
<tr>
tag più tutto il resto.
Che cosa mi manca del motivo per cui il flusso di dati a senso unico è (visto come) significativamente più performante rispetto al collegamento bidirezionale dei dati con il controllo sporco?