Я нашел несколько реализаций, AuthGuard
которые используют take(1)
. В своем проекте я использовал first()
.
Оба работают одинаково?
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AngularFire } from 'angularfire2';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private angularFire: AngularFire, private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
return this.angularFire.auth.map(
(auth) => {
if (auth) {
this.router.navigate(['/dashboard']);
return false;
} else {
return true;
}
}
).first(); // Just change this to .take(1)
}
}
angular
rxjs
angular2-observables
Karuban
источник
источник
first()
иtake()
в целом они такие же, что я думаю, очевидно, только то, чтоfirst()
иtake(1)
такие же. Я не уверен в вашем ответе, считаете ли вы, что разница все еще есть?first()
отправьте уведомление об ошибке, покаtake(1)
просто ничего не испускает.first()
. Если это допустимое состояние приложения, я бы выбралtake(1)
..First()
vs.FirstOrDefault()
(и, если подумать, это еще и.Take(1)
то, что First требует что-то в коллекции и выдает ошибку для пустой коллекции - и то и другое,FirstOrDefault()
и.Take(1)
позволяет коллекции быть пустой и возвращатьnull
и пустую коллекцию соответственно.Совет: используйте только
first()
если:Если выбросы нулевые и вы явно не обрабатываете их (с помощью
catchError
), то эта ошибка будет распространяться вверх, возможно, вызовет неожиданную проблему в другом месте, и ее может быть довольно сложно отследить, особенно если она исходит от конечного пользователя.По большей части вы безопаснее использовать
take(1)
при условии, что:take(1)
если ничего не испускаете, если источник завершается без эмиссии.first(x => x > 10)
).Примечание: Вы можете использовать предикат с
take(1)
так:.pipe( filter(x => x > 10), take(1) )
. Это не приведет к ошибке, если ничто не превышает 10.Что о
single()
Если вы хотите быть еще строже и запретить два выброса, вы можете использовать
single()
какие ошибки, если выбросы равны нулю или 2+ . В этом случае вам снова придется обрабатывать ошибки.Совет:
Single
иногда может быть полезен, если вы хотите, чтобы ваша наблюдаемая цепочка не выполняла лишнюю работу, например, дважды вызывала http-службу и генерировала две наблюдаемые. Добавлениеsingle
на конец трубы сообщит вам, если вы сделали такую ошибку. Я использую его в «средстве выполнения задач», где вы передаете наблюдаемую задачу, которая должна выдавать только одно значение, поэтому я передаю ответ,single(), catchError()
чтобы гарантировать хорошее поведение.Почему бы всегда не использовать
first()
вместоtake(1)
?ака. Как
first
потенциально может вызвать больше ошибок?Если у вас есть наблюдаемый объект, который берет что-то из службы, а затем передает это по
first()
конвейеру, в большинстве случаев все будет в порядке. Но если кто-то по какой-то причине придет и отключит службу - и изменит ее на emit,of(null)
иначеNEVER
любые последующиеfirst()
операторы начнут выдавать ошибки.Теперь я понимаю, что это может быть именно то , что вам нужно, поэтому это всего лишь подсказка. Оператор
first
обратился ко мне, потому что это звучало немного менее «неуклюже», чем,take(1)
но вам нужно быть осторожным с обработкой ошибок, если когда-либо есть вероятность того, что источник не будет излучать. Однако все будет зависеть от того, что вы делаете.Если у вас есть значение по умолчанию (константа):
Также
.pipe(defaultIfEmpty(42), first())
подумайте, есть ли у вас значение по умолчанию, которое следует использовать, если ничего не испускается. Это, конечно, не вызовет ошибку, потомуfirst
что всегда будет получать значение.Обратите внимание, что
defaultIfEmpty
запускается только в том случае, если поток пуст, а не в том случае, если значение того, что испускается, равноnull
.источник
single
здесь больше различийfirst
. 1. Он будет выдавать только значениеcomplete
. Это означает, что если наблюдаемый излучает значение, но никогда не завершается, то single никогда не будет генерировать значение. 2. По какой-то причине, если вы передадите функцию фильтра,single
которой ничего не соответствует, она выдастundefined
значение, если исходная последовательность не пуста, что не относится к случаюfirst
.Вот три Observables
A
,B
иC
с мраморными диаграммами, чтобы изучить разницу междуfirst
,take
иsingle
операторы:* Легенда :
--o--
значение----!
ошибки----|
завершенияПоиграйте с ним на https://thinkrx.io/rxjs/first-vs-take-vs-single/ .
Уже имея все ответы, я хотел добавить более наглядное объяснение
Надеюсь, это кому-то поможет
источник
Есть одно действительно важное отличие, о котором нигде не упоминается.
take (1) излучает 1, завершает, отписывается
first () выдает 1, завершает, но не отказывается от подписки.
Это означает, что ваш наблюдаемый в восходящем направлении будет все еще активен после first (), что, вероятно, не является ожидаемым поведением.
UPD: это относится к RxJS 5.2.0. Эта проблема может быть уже исправлена.
источник
Похоже, что в RxJS 5.2.0 у
.first()
оператора есть ошибка ,Из-за этой ошибки
.take(1)
и.first()
может вести себя совершенно иначе, если вы используете их сswitchMap
:С
take(1)
вы получите ожидаемое поведение:Но с
.first()
вами будет неправильное поведение:Вот ссылка на код
источник