Подтвердить что ты не робот

Нужно ли отписываться от наблюдаемых, созданных методами Http?

Вам нужно отписаться от 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());
            ...
4b9b3361

Ответ 1

Так что ответ - нет. Ng2 его очистит.

Источник службы Http из внутреннего источника Angular Http XHR:

enter image description here

Обратите внимание, как он выполняет complete() после получения результата. Это означает, что на самом деле отписывается по завершении. Так что вам не нужно делать это самостоятельно.

Вот тест для проверки:

  fetchFilms() {
    return (dispatch) => {
        dispatch(this.requestFilms());

        let observer = this._http.get('${BASE_URL}')
            .map(result => result.json())
            .map(json => {
                dispatch(this.receiveFilms(json.results));
                dispatch(this.receiveNumberOfFilms(json.count));
                console.log("2 isUnsubscribed",observer.isUnsubscribed);
                window.setTimeout(() => {
                  console.log("3 isUnsubscribed",observer.isUnsubscribed);
                },10);
            })
            .subscribe();
        console.log("1 isUnsubscribed",observer.isUnsubscribed);
    };
}

Как и ожидалось, вы можете видеть, что он всегда отписывается автоматически после получения результата и завершения с наблюдаемыми операторами. Это происходит по таймауту (# 3), поэтому мы можем проверить состояние наблюдаемого, когда все это сделано и завершено.

И результат

enter image description here

Таким образом, никакой утечки не будет, поскольку Ng2 автоматически отписывается!

Приятно отметить: Это Observable классифицируются как finite, напротив к infinite Observable, который является бесконечным поток данных может посылаться как DOM click слушатель, например.

СПАСИБО, @rubyboy за помощь в этом.

Ответ 2

О чем вы, люди, говорите !!!

ОК, так что есть две причины отписаться от любого наблюдаемого. Никто, кажется, не говорит много об очень важной второй причине!

1) Очистить ресурсы. Как уже говорили другие, это незначительная проблема для наблюдаемых HTTP. Это просто очистит себя.

2) Предотвратить запуск обработчика subscribe.

(Для HTTP это на самом деле также отменит запрос в браузере - так что это не будет тратить время на чтение ответа. Но это на самом деле в стороне от моего основного пункта ниже.)

Актуальность номера 2 будет зависеть от того, что делает ваш обработчик подписки:

Если ваша функция-обработчик subscribe() имеет какой-либо побочный эффект, который нежелателен, если какие-либо вызовы закрыты или утилизированы, вы должны отписаться (или добавить условную логику), чтобы предотвратить ее выполнение.

Рассмотрим несколько случаев:

1) Форма входа. Вы вводите имя пользователя и пароль и нажимаете "Войти". Что если сервер работает медленно и вы решите нажать Escape, чтобы закрыть диалоговое окно? Вы, вероятно, предположите, что вы не вошли в систему, но если http-запрос вернется после того, как вы нажмете escape, тогда вы все равно будете выполнять ту логику, которая у вас есть. Это может привести к перенаправлению на страницу учетной записи, установке нежелательного файла cookie для входа в систему или переменной токена. Это, вероятно, не то, что ожидал ваш пользователь.

2) Форма для отправки электронной почты.

Если обработчик subscribe для "sendEmail" выполняет что-то вроде запуска анимации "Ваше письмо отправлено", переносит вас на другую страницу или пытается получить доступ ко всему, что было удалено, вы можете получить исключения или нежелательное поведение.

Также будьте осторожны, чтобы не предполагать, что unsubscribe() означает "отмена". Как только сообщение HTTP будет в полете, unsubscribe() НЕ отменит запрос HTTP, если он уже достиг вашего сервера. Это только отменит ответ, возвращающийся к вам. И письмо, вероятно, будет отправлено.

Если вы создаете подписку для отправки электронной почты непосредственно внутри компонента пользовательского интерфейса, вы, вероятно, захотите отменить подписку при утилизации, но если электронная почта отправляется нецентрализованной службой, то вам, вероятно, не понадобится.

3) Угловой компонент, который разрушен/закрыт. Любые наблюдаемые http, которые все еще работают в то время, завершат и запустят свою логику, если вы не onDestroy() подписку в onDestroy(). Будут ли последствия тривиальными или нет, будет зависеть от того, что вы делаете в обработчике подписки. Если вы попытаетесь обновить то, что больше не существует, вы можете получить ошибку.

Иногда у вас могут быть какие-то действия, которые вы захотите, если компонент удаляется, а некоторые - нет. Например, может быть, у вас есть звук "swoosh" для отправленного электронного письма. Возможно, вы захотите, чтобы это воспроизводилось, даже если компонент был закрыт, но если вы попытаетесь запустить анимацию на компоненте, это не получится. В этом случае некоторой дополнительной условной логикой внутри подписки будет решение - и вы не захотите отписываться от наблюдаемой http.

Таким образом, в ответ на фактический вопрос, нет, вам не нужно делать это, чтобы избежать утечек памяти. Но вы должны делать это (часто), чтобы избежать нежелательных побочных эффектов, вызванных выполнением кода, который может вызвать исключения или испортить состояние вашего приложения.

Совет: Subscription содержит closed логическое свойство, которое может быть полезно в сложных случаях. Для HTTP это будет установлено после завершения. В Угловое может быть полезно в некоторых ситуациях, чтобы установить _isDestroyed свойство в ngDestroy, которые могут быть проверены с помощью вашей subscribe обработчика.

Совет 2. Если вы обрабатываете несколько подписок, вы можете создать специальный new Subscription() объект new Subscription() и add(...) любые другие подписки к нему - поэтому, когда вы отмените подписку на основную, она также отменит все добавленные подписки.

Ответ 3

Вызов метода unsubscribe скорее должен отменить HTTP-запрос в процессе выполнения, так как этот метод вызывает abort один на базовом объекте XHR и удаляет слушатели при событиях загрузки и ошибки:

// From the XHRConnection class
return () => {
  _xhr.removeEventListener('load', onLoad);
  _xhr.removeEventListener('error', onError);
  _xhr.abort();
};

Тем не менее, unsubscribe удаляет слушателей... Так что это может быть хорошей идеей, но я не думаю, что это необходимо для одного запроса; -)

Надеюсь, это поможет вам, Thierry

Ответ 4

Также с новым модулем HttpClient, остается то же самое поведение packages/common/http/src/jsonp.ts

Ответ 5

Вы не должны отписываться от наблюдаемых, которые завершаются автоматически (например, Http, звонки). Но необходимо отписаться от бесконечных наблюдаемых, таких как Observable.timer().

Ответ 6

Вы обязательно должны прочитать эту статью. Он показывает, почему вы всегда должны отписаться даже от http.

Если после создания запроса, но до получения ответа от серверной части, вы посчитаете компонент ненужным и уничтожите его, ваша подписка сохранит ссылку на компонент, создавая тем самым возможность вызвать утечки памяти.

Обновить

Приведенное выше утверждение кажется верным, но в любом случае, когда ответ возвращается, подписка http все равно уничтожается

Ответ 7

Отказ от подписки является обязательным MUST, если вы хотите детерминистическое поведение на всех скоростях сети.

Представьте,, что компонент A отображается на вкладке. Вы нажимаете кнопку, чтобы отправить запрос "GET". Для ответа требуется 200 мс. Таким образом, вы можете безопасно закрыть вкладку в любой момент, зная, что машина будет работать быстрее, чем вы. http-ответ обрабатывается и завершается до закрытия вкладки и уничтожения компонента A.

Как насчет очень медленной сети? Вы нажимаете кнопку, запрос "GET" занимает 10 секунд, чтобы получить ответ, но через 5 секунд ожидания вы решаете закрыть вкладку. Это уничтожит компонент А для последующего сбора мусора. Подожди минутку!, мы не отписались - теперь через 5 секунд ответ возвращается и логика в уничтоженном компоненте будет выполнена. Это выполнение теперь считается out-of-context и может привести ко многим вещам, включая очень низкую производительность.

Таким образом, наилучшей практикой является использование takeUntil() и отмена подписки на вызовы http, когда компонент уничтожен.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

interface User {
  id: string;
  name: string;
  age: number;
}

@Component({
  selector: 'app-foobar',
  templateUrl: './foobar.component.html',
  styleUrls: ['./foobar.component.scss'],
})
export class FoobarComponent implements OnInit, OnDestroy {
  private user: User = null;
  private destroy$ = new Subject();

  constructor(private http: HttpClient) {}

  ngOnInit() {
    this.http
      .get<User>('api/user/id')
      .pipe(takeUntil(this.destroy$))
      .subscribe(user => {
        this.user = user;
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();  // trigger the unsubscribe
    this.destroy$.complete(); // finalize & clean up the subject stream
  }
}

Ответ 8

40 голосов "за": " Нет, не вы", "195" за " да", что очень смущает эту тему.

Почему у нас не может быть ни одного утверждения, которое бы советовало хорошую практику и однозначно отвечает на вопрос

Ответ 9

Наблюдаемые RxJS в основном связаны и работают соответственно подписке. Когда мы создаем наблюдаемое, а движение мы его завершаем, наблюдаемое автоматически закрывается и отписывается.

Они работают так же, как наблюдатели, но в совершенно ином порядке. Лучшая практика - отписаться от них, когда компонент становится уничтоженным. Впоследствии мы можем сделать это, например. это. $ manageSubscription.unsubscibe()

Если мы создали наблюдаемый, как приведенный ниже синтаксис, такой как

** возвращаем новое Наблюдаемое ((наблюдатель) => {**//Делает наблюдаемое в холодном состоянии ** Наблюдатель .complete() **}) **