Зоны в угловых
- Какие зоны?
- Чем угловой ngZone отличается от zone.js?
- Когда их следует использовать? Может кто-нибудь помочь с практическими примерами использования ngZone?
Однако я просмотрел здесь угловую документацию и не смог получить полного понимания.
2 ответа
NgZone
является оберткой вокруг Zone.js, которая является библиотекой, которая создает контекст вокруг асинхронных функций, чтобы сделать их отслеживаемыми.
Обнаружение изменений Angular сильно зависит от Zones
, Как?
Angular нужен способ понять, когда пора запускать обнаружение изменений, что по сути лишь обновление DOM
представлять последние изменения модели ( javascript).
Представьте, что у нас есть приведенный ниже пример:
<div id="content"></div>
И где-то в нашем коде JavaScript мы имеем
const element = document.getElementById('content');
function updateText(){
element.innerHtml = myText+ ": updated at time"+Date.now()
}
Скажем, изначально я собираюсь обновить content
с приветом:
const myText = "Hello";
this.updateText();
Это обновит мой HTML-контент до текста: "Здравствуйте, обновлено в 19:30"
а потом, скажем, я хочу обновить myText
переменная, которая будет чем-то другим после щелчка пользователя:
<button onClick="updateTheTextAgain()"></button>
updateTheTextAgain(){
this.myText = "Hi there";
}
Что случится, если я нажму на эту кнопку?
Ничего;
Ну, на самом деле это не "ничего", мне удалось обновить переменную, но я НЕ обновлял представление (я не обнаружил изменения модели), поэтому мне нужно настроить updateTheTextAgain
быть:
updateTheTextAgain(){
this.myText = "Hi there";
this.updateText(); /// Making sure I'm detecting the change ( I'm updating the `DOM`)
}
Теперь нажатие на кнопку обновит мой вид (из-за обнаружения изменений вручную).
Это, очевидно, не лучшая идея, потому что тогда я должен написать много updateText
функции и вызывать их везде, где я хочу, чтобы представление обновлялось после обновления модели, верно (Вернитесь к Angular1 и запомните $scope.apply()
)?
Вот где ZoneJs
удивительно.
Представь, если бы я мог переписать onClick
Я имею в виду оригинальную функцию браузера onClick:
const originalOnClick = window.onClick;
window.onClick = function(){
originalOnClick();
this. updateText();
}
Это называется monkey patching
или же open heart surgery
нативных функций.
Что я получаю от этого?
После того, как я положил patched onClick
на странице все onClick
Функция, которая будет написана во всем приложении, собирается пройти через мой patched onClick
значит, мне не нужно бежать updateText()
функционировать после каждого щелчка, потому что он запекается в click
Сам обработчик событий.
В Angular это updateText
это change detection
Angular имеет хуки во всех нативных событиях (используя Zones).
Поэтому, когда вы пишете:
setTimeout(()=>{
console.log('Do something');
},100);
На самом деле вы пишете что-то вроде:
setTimeout(()=>{
console.log('Do something');
runAngularsChangeDetection();
},100);
Выше очень далеко, что происходит в реальности, но это сердце всей истории обнаружения изменений и Zones
и зачем они нам нужны /
** ОБНОВИТЬ:**
Когда мы должны использовать NgZone
,
Там будет много случаев, когда вы хотите использовать NgZone
Я могу назвать два:
1- Когда вы хотите, чтобы что-то вышло за пределы обнаружения изменений Angular:
Помните, я говорил, что Angular имеет хуки во всех асинхронных событиях? window.onScroll
это один из них, теперь давайте предположим, что мы хотим сделать некоторые вычисления, когда пользователь выполняет прокрутку, что вы обычно делаете:
window.onscroll = ()=>{
// do some heavy calculation :
}
Теперь при прокрутке ваша функция вызывается нормально, как и следовало ожидать, но вы можете заметить, что у вас возникает проблема с производительностью, и это может быть из-за того, что Angular запускает changeDetection
на каждое событие прокрутки (ожидаемое поведение).
Если в вашем компоненте много привязок, то вы наверняка заметите падение производительности на свитке.
Так что один из способов сказать, эй Angular, игнорировать мой onscroll
событие, я знаю, что я делаю, я не хочу, чтобы вы запускали обнаружение изменений, в этом случае вы бы использовали NgZone
constructor(private zone:NgZone){
this.zone.runOutsideOfAngular(()=>{
window.onscroll = ()=>{
// do some heavy calculation :
}
})
}
Это позволит Angular не запускать обнаружение изменений при прокрутке.
Другой случай был бы полностью противоположен приведенному выше, когда у вас есть функция, которая каким-то образом находится вне зоны Angular, и вы хотите, чтобы она была внутри, например, когда сторонняя библиотека делает что-то для вас, и вы хотите, чтобы она была связана с Ваш угловой цикл.
this.zone.run(()=>{
$.get('someUrl').then(()=>{
this.myViewVariable = "updated";
})
});
Без использования Zone вам, скорее всего, нужно сделать:
$.get('someUrl').then(()=>{
this.myViewVariable = "updated";
this.changeDetectorRef.detectChanges();
})
Но обратите внимание, что когда ваша функция находится внутри зоны (метод run), вам не нужно вызывать detectChanges
Вручную самостоятельно и угловатые сделают всю работу
Текущий официальный документ не на должном уровне. Есть люди, которые делают сумасшедшие вещи в Angular, и Pascal Precht тоже. Его статья ниже поможет вам понять, что такое Zone
а также ngZone
,
https://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html