Вам нужно отписаться от Angular 2 http-вызовов, чтобы предотвратить утечку памяти?
fetchFilm(index) {
var sub = this._http.get(`http://example.com`)
.map(result => result.json())
.map(json => {
dispatch(this.receiveFilm(json));
})
.subscribe(e=>sub.unsubscribe());
...
angular
memory-leaks
rxjs
angular2-http
born2net
источник
источник
Ответы:
Так что ответ - нет.
Ng2
уберусь сам.Источник службы Http из внутреннего источника Angular's Http XHR:
Обратите внимание, как он работает
complete()
после получения результата. Это означает, что на самом деле отписывается по завершении. Так что вам не нужно делать это самостоятельно.Вот тест для проверки:
Как и ожидалось, вы можете видеть, что он всегда отписывается автоматически после получения результата и завершения с наблюдаемыми операторами. Это происходит по таймауту (# 3), поэтому мы можем проверить состояние наблюдаемого, когда все это сделано и завершено.
И результат
Так что никакой утечки не будет, так как
Ng2
авто отписался!Приятно упомянуть: это
Observable
классифицируется какfinite
, в отличие отinfinite
Observable
бесконечного потока данных, которые могут передаваться, например,click
слушатель DOM .СПАСИБО, @rubyboy за помощь в этом.
источник
О чем вы, люди, говорите !!!
Итак, есть две причины отписаться от любого наблюдаемого. Никто, кажется, не говорит много об очень важной второй причине!
(Для HTTP это на самом деле также отменит запрос в браузере - так что это не будет тратить время на чтение ответа. Но это на самом деле в стороне от моего основного пункта ниже.)
Актуальность номера 2 будет зависеть от того, что делает ваш обработчик подписки:
Рассмотрим несколько случаев:
1) Форма входа. Вы вводите имя пользователя и пароль и нажимаете «Войти». Что если сервер работает медленно и вы решите нажать Escape, чтобы закрыть диалоговое окно? Вы, вероятно, предположите, что вы не вошли в систему, но если запрос http вернется после того, как вы нажмете escape, тогда вы все равно будете выполнять ту логику, которая у вас есть. Это может привести к перенаправлению на страницу учетной записи, установке нежелательного файла cookie для входа в систему или переменной токена. Это, вероятно, не то, что ожидал ваш пользователь.
2) Форма для отправки по электронной почте.
Если
subscribe
обработчик для «sendEmail» делает что-то вроде запуска анимации «Ваше письмо отправлено», переносит вас на другую страницу или пытается получить доступ ко всему, что было удалено, вы можете получить исключения или нежелательное поведение.Также будьте осторожны, чтобы не принять
unsubscribe()
означает «отменить». Как только HTTP-сообщение находится в полетеunsubscribe()
, НЕ отменяет HTTP-запрос, если он уже достигнут вашего сервера. Это только отменит ответ, возвращающийся к вам. И письмо, вероятно, будет отправлено.Если вы создаете подписку для отправки электронной почты непосредственно в компоненте пользовательского интерфейса, вы, вероятно, захотите отменить подписку при утилизации, но если электронная почта отправляется нецентрализованной службой, то вам, вероятно, не понадобится.
3) Угловой компонент, который разрушен / закрыт. Любые наблюдаемые http, которые все еще работают в то время, завершат и запустят свою логику, если вы не отмените подписку
onDestroy()
. Будут ли последствия тривиальными или нет, будет зависеть от того, что вы делаете в обработчике подписки. Если вы попытаетесь обновить то, что больше не существует, вы можете получить ошибку.Иногда у вас могут быть какие-то действия, которые вы захотите, если компонент удаляется, а некоторые - нет. Например, может быть, у вас есть звук «swoosh» для отправленного электронного письма. Возможно, вы захотите, чтобы это воспроизводилось, даже если компонент был закрыт, но если вы попытаетесь запустить анимацию на компоненте, это не получится. В этом случае некоторая дополнительная условная логика внутри подписки будет решением - и вы НЕ захотите отписываться от наблюдаемой http.
Поэтому, отвечая на реальный вопрос, нет необходимости делать это, чтобы избежать утечек памяти. Но вы должны делать это (часто), чтобы избежать нежелательных побочных эффектов, вызванных выполнением кода, который может вызвать исключения или испортить состояние вашего приложения.
Совет:
Subscription
Содержитclosed
логическое свойство, которое может быть полезно в сложных случаях. Для HTTP это будет установлено после завершения. В Angular может быть полезно в некоторых ситуациях установить_isDestroyed
свойство,ngDestroy
которое может быть проверено вашимsubscribe
обработчиком.Совет 2. Если вы обрабатываете несколько подписок, вы можете создать специальный
new Subscription()
объект иadd(...)
любые другие подписки на него - поэтому, когда вы отмените подписку на основную, она также отменит все добавленные подписки.источник
Вызов
unsubscribe
метода скорее отменяет выполняющийся HTTP-запрос, так как этот метод вызывает тотabort
из базового объекта XHR и удаляет прослушиватели событий load и error:Тем не менее,
unsubscribe
удаляет слушателей ... Так что это может быть хорошей идеей, но я не думаю, что это необходимо для одного запроса ;-)Надеюсь, это поможет тебе, Тьерри
источник
y = x.subscribe((x)=>data = x);
тогда пользователь изменил входные данные и,x.subscribe((x)=>cachlist[n] = x); y.unsubscribe()
эй, вы использовали наши ресурсы сервера, я выиграл не выбрасываю тебя ..... и в другом сценарии: просто позвони,y.stop()
выбрасывай все прочьОтказ от подписки является обязательным , если вы хотите детерминированное поведение на всех скоростях сети.
Представьте, что компонент A отображается на вкладке. Вы нажимаете кнопку, чтобы отправить запрос «GET». Для ответа требуется 200 мс. Таким образом, вы можете безопасно закрыть вкладку в любой момент, зная, что машина будет работать быстрее, чем вы, и http-ответ будет обработан и завершится до закрытия вкладки и уничтожения компонента A.
Как насчет очень медленной сети? При нажатии кнопки запрос «GET» занимает 10 секунд для получения ответа, но через 5 секунд ожидания вы решаете закрыть вкладку. Это уничтожит компонент А для последующего сбора мусора. Подожди минуту! Мы не отписались - теперь через 5 секунд возвращается ответ и логика в уничтоженном компоненте будет выполнена. Это выполнение теперь рассматривается
out-of-context
и может привести ко многим вещам, включая очень низкую производительность.Таким образом, лучшая практика заключается в использовании
takeUntil()
и отмене подписки на вызовы http, когда компонент уничтожен.источник
BehaviorSubject()
вместо этого и позвонить толькоcomplete()
вngOnDestroy()
?BehaviourSubject
иначе?Также с новым модулем HttpClient, остается то же самое поведение
источник
Вы не должны отписываться от наблюдаемых, которые завершаются автоматически (например, Http, звонки). Но отписаться от бесконечных наблюдаемых вроде надо
Observable.timer()
.источник
После некоторого времени тестирования, чтения документации и исходного кода HttpClient.
HttpClient:
https://github.com/angular/angular/blob/master/packages/common/http/src/client.tsHttpXhrBackend :
https://github.com/angular/angular/blob/master/packages/common/http/src/xhr.tsHttpClientModule
: https://indepth.dev/exploring-the-httpclientmodule-in-angular/Угловой университет: https://blog.angular-university.io/angular-http/
И ответ на весь вопрос "нужно ли мне" отписаться?
Это зависит. Http вызов Memoryleaks не проблема. Проблемы - логика в ваших функциях обратного вызова.
Например: Маршрутизация или Логин.
Если ваш звонок является входящим вызовом, вам не нужно «отписываться», но вы должны убедиться, что если пользователь покидает страницу, вы правильно обрабатываете ответ в отсутствие пользователя.
От раздражающего к опасному
А теперь представьте, что сеть медленнее, чем обычно, вызов занимает больше 5 секунд, и пользователь покидает окно входа в систему и переходит в «представление поддержки».
Компонент может быть не активным, но подписка. В случае ответа пользователь будет внезапно перенаправлен (в зависимости от вашей реализации handleResponse ()).
Это не хорошо
Также представьте, что пользователь покидает компьютер, полагая, что он еще не вошел в систему. Но вы логически входите в систему пользователя, теперь у вас есть проблемы с безопасностью.
Что можно сделать БЕЗ отписки?
Звонок зависит от текущего состояния просмотра:
Пользователь
.pipe(takeWhile(value => this.isActive))
должен убедиться, что ответ обрабатывается только при активном представлении.Но как вы можете быть уверены, что подписка не вызывает утечек памяти?
Вы можете войти, если применяется teardownLogic.
TeardownLogic подписки вызывается, когда подписка пуста или отписана.
Вам не нужно отписываться. Вы должны знать, есть ли проблемы в вашей логике, которые могут вызвать проблемы в вашей подписке. И позаботься о них. В большинстве случаев это не будет проблемой, но особенно в критических задачах, таких как авторизация, вы должны позаботиться о непредвиденном поведении, помешать его «отписаться» или другой логике, такой как конвейер или функции условного обратного вызова.
почему просто не всегда отписаться?
Представьте, что вы делаете запрос на размещение или публикацию. Сервер получает сообщение в любом случае, только ответ занимает некоторое время. Отписаться, не отменить сообщение или положить. Но когда вы отмените подписку, у вас не будет возможности обработать ответ или проинформировать пользователя, например, через диалог, тост / сообщение и т. Д.
Это заставляет Пользователя полагать, что запрос на размещение / публикацию не был выполнен.
Так что это зависит. Это ваше дизайнерское решение, как бороться с такими проблемами.
источник
Вы обязательно должны прочитать эту статью. Он показывает, почему вы всегда должны отписаться даже от http .
Обновить
Приведенное выше утверждение кажется верным, но в любом случае, когда ответ возвращается, подписка http все равно уничтожается
источник
Наблюдаемые RxJS в основном связаны и работают соответственно подписке. Когда мы создаем наблюдаемое, а движение мы его завершаем, наблюдаемое автоматически закрывается и отписывается.
Они работают так же, как наблюдатели, но в совершенно другом порядке. Лучшая практика - отписаться от них, когда компонент становится уничтоженным. Впоследствии мы можем сделать это, например ,. это. $ manageSubscription.unsubscibe ()
Если мы создали наблюдаемый, как приведенный ниже синтаксис, такой как
** возвращаем новое Наблюдаемое ((наблюдатель) => {** // Делает наблюдаемое в холодном состоянии ** Наблюдатель.complete () **}) **
источник