ले (1) बनाम पहले ()


137

मुझे 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)
    }
}

जवाबों:


197

ऑपरेटर first()और take(1)समान नहीं हैं।

first()ऑपरेटर एक वैकल्पिक लेता है predicateसमारोह और एक का उत्सर्जन करता है errorजब कोई मूल्य नहीं जब स्रोत पूरा मिलान किया अधिसूचना।

उदाहरण के लिए यह एक त्रुटि का उत्सर्जन करेगा:

import { EMPTY, range } from 'rxjs';
import { first, take } from 'rxjs/operators';

EMPTY.pipe(
  first(),
).subscribe(console.log, err => console.log('Error', err));

... साथ में यह भी:

range(1, 5).pipe(
  first(val => val > 6),
).subscribe(console.log, err => console.log('Error', err));

जबकि यह उत्सर्जित पहले मूल्य से मेल खाएगा:

range(1, 5).pipe(
  first(),
).subscribe(console.log, err => console.log('Error', err));

दूसरी ओर take(1)सिर्फ पहला मूल्य लेता है और पूरा करता है। कोई और तर्क शामिल नहीं है।

range(1, 5).pipe(
  take(1),
).subscribe(console.log, err => console.log('Error', err));

फिर खाली स्रोत के साथ अवलोकन योग्य यह किसी भी त्रुटि का उत्सर्जन नहीं करेगा:

EMPTY.pipe(
  take(1),
).subscribe(console.log, err => console.log('Error', err));

जनवरी 2019: आरएक्सजेएस 6 के लिए अपडेट किया गया


2
बस नोट के रूप में, मुझे लगता है कि ऐसा नहीं कहा first()और take()सामान्य रूप में एक ही है, जो मुझे लगता है कि स्पष्ट है, केवल कि कर रहे हैं first()और take(1)एक ही हैं। अगर आपको लगता है कि अभी भी कोई अंतर है तो मुझे आपके जवाब से यकीन नहीं होगा?
गुंटर ज़ोचबॉयर

14
@ गुंटरेज़ोचाउर दरअसल, उनका व्यवहार अलग है। यदि स्रोत कुछ भी उत्सर्जित नहीं करता है और पूर्ण हो जाता है तो first()त्रुटि सूचना भेजें जबकि take(1)बस कुछ भी उत्सर्जित नहीं करेगा।
मार्टिन

@ स्मार्टिन, कुछ मामलों में (1) कुछ भी नहीं कहेगा कि कोड को डीबग करना कठिन होगा?
करुणा

7
@ कर्बन यह वास्तव में आपके usecase पर निर्भर करता है। किसी भी मूल्य प्राप्त नहीं है, तो अप्रत्याशित की तुलना में मैं उपयोग करने के लिए सुझाव देंगे है first()। यदि यह एक वैध अनुप्रयोग स्थिति है तो मैं जाऊंगा take(1)
मार्टिन

2
यह .NET के .First()बनाम के समान है .FirstOrDefault()(और इसके बारे में यह भी सोचें .Take(1)कि पहले संग्रह में कुछ की आवश्यकता है और एक खाली संग्रह के लिए एक त्रुटि देता है - और दोनों FirstOrDefault()और .Take(1)संग्रह को खाली करने और nullक्रमशः लौटने और खाली संग्रह करने की अनुमति देता है।
Simon_Weaver

45

युक्ति: केवल तभी उपयोग करें first()यदि:

  • आप शून्य आइटम को एक त्रुटि स्थिति मानते हैं (जैसे कि उत्सर्जन करने से पहले पूरा करना) और यदि आप इसे ग्रेसफुल तरीके से हैंडल करने का 0% से अधिक मौका है
  • या आप 100% जानते हैं कि अवलोकनीय स्रोत 1+ आइटम का उत्सर्जन करेगा (इसलिए कभी भी फेंक नहीं सकता)

यदि शून्य उत्सर्जन हैं और आप इसे (इसके साथ 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()आपके माध्यम से इसे पाइप करता है तो अधिकांश समय ठीक होना चाहिए। लेकिन अगर कोई भी किसी भी कारण से सेवा को निष्क्रिय करने के लिए आता है - और इसे बदलने के लिए of(null)या NEVERफिर किसी भी डाउनस्ट्रीम first()ऑपरेटर त्रुटियों को फेंकना शुरू कर देगा।

अब मुझे एहसास हुआ कि जैसा आप चाहते हैं वैसा ही हो सकता है - इसलिए यह सिर्फ एक टिप है। ऑपरेटर firstने मुझसे अपील की, क्योंकि यह 'कम अनाड़ी' लग रहा था, take(1)लेकिन आपको त्रुटियों से निपटने के बारे में सावधान रहने की ज़रूरत है अगर कभी स्रोत से बाहर निकलने का मौका न हो। पूरी तरह से इस बात पर निर्भर करेगा कि आप क्या कर रहे हैं।


यदि आपके पास एक डिफ़ॉल्ट मान (स्थिर) है:

यह भी विचार करें .pipe(defaultIfEmpty(42), first())कि क्या आपके पास एक डिफ़ॉल्ट मान है जिसका उपयोग किया जाना चाहिए यदि कुछ भी उत्सर्जित नहीं होता है। यह निश्चित रूप से एक त्रुटि नहीं बढ़ाएगा क्योंकि firstहमेशा एक मूल्य प्राप्त होगा।

ध्यान दें कि defaultIfEmptyयदि धारा खाली है तो केवल ट्रिगर किया जाता है, यदि उत्सर्जित होने का मूल्य नहीं है null


इस बात से अवगत रहें कि singleअधिक अंतर है first1. यह केवल मूल्य का उत्सर्जन करेगा complete। इसका मतलब यह है कि अगर अवलोकन योग्य मूल्य का उत्सर्जन होता है लेकिन कभी पूरा नहीं होता है तो एकल कभी भी मूल्य का उत्सर्जन नहीं करेगा। 2. किसी कारण से यदि आप एक फिल्टर फंक्शन पास करते हैं, singleजिसमें कुछ भी मेल नहीं खाता है, तो यह एक undefinedमान का उत्सर्जन करेगा यदि मूल अनुक्रम खाली नहीं है, जो कि ऐसा नहीं है first
मैरिनो एक

28

यहाँ तीन observables हैं A, Bऔर Cसंगमरमर चित्र के साथ के बीच अंतर का पता लगाने के first, takeऔर singleऑपरेटरों:

पहले बनाम एकल ऑपरेटरों की तुलना करें

* किंवदंती :
--o-- मूल्य
----! त्रुटि
----| पूर्णता

Https://thinkrx.io/rxjs/first-vs-take-vs-single/ पर इसके साथ खेलें ।

पहले से ही सभी उत्तर होने के बाद, मैं एक अधिक दृश्य स्पष्टीकरण जोड़ना चाहता था

आशा है कि यह किसी की मदद करता है


12

वहाँ एक बहुत महत्वपूर्ण अंतर है जो कहीं भी उल्लेख नहीं किया गया है।

ले (1) 1 का उत्सर्जन करता है, पूरा करता है, सदस्यता समाप्त करता है

पहला () 1 निकलता है, पूरा होता है, लेकिन सदस्यता समाप्त नहीं करता है।

इसका मतलब है कि आपका अपस्ट्रीम देखने योग्य पहले के बाद भी गर्म रहेगा () जो कि अपेक्षित व्यवहार नहीं है।

UPD: इसका संदर्भ RxJS 5.2.0 है। यह समस्या पहले से तय हो सकती है।


मुझे नहीं लगता है कि या तो एक सदस्यता रद्द करें, jsbin.com/nuzulorota/1/edit?js,console देखें ।
वेल्ट्सकेमरज़

10
हां, दोनों ऑपरेटर सदस्यता को पूरा करते हैं, अंतर त्रुटि हैंडलिंग में होता है। यदि वह अवलोकनीय मानों का उत्सर्जन नहीं करता है और फिर भी पहले ऑपरेटर का उपयोग करके पहला मान लेने की कोशिश करता है तो यह एक त्रुटि फेंक देगा। यदि हम इसे (1) ऑपरेटर के साथ प्रतिस्थापित करते हैं, भले ही मूल्य धारा में नहीं है जब सदस्यता होती है तो यह एक त्रुटि नहीं करता है।
नोहलहान

7
स्पष्ट करने के लिए: दोनों ही सदस्यता समाप्त करते हैं। @Weltschmerz से उदाहरण बहुत सरल किया गया था, यह तब तक नहीं चलता है जब तक कि यह अपने आप से समाप्त न हो जाए। यह एक और अधिक विस्तारित है: repl.it/repls/FrayedHugeAudacity
स्टीफ़न एल.वी.

10

ऐसा लगता है कि RxJS 5.2.0 में .first()ऑपरेटर के पास बग है ,

उस बग के कारण .take(1)और .first()यदि आप उनके साथ उपयोग कर रहे हैं तो काफी अलग व्यवहार कर सकते हैं switchMap:

साथ take(1)की उम्मीद के रूप में आप व्यवहार मिल जाएगा:

var x = Rx.Observable.interval(1000)
   .do( x=> console.log("One"))
   .take(1)
   .switchMap(x => Rx.Observable.interval(1000))
   .do( x=> console.log("Two"))
   .subscribe((x) => {})

// In the console you will see:
// One
// Two
// Two
// Two
// Two
// etc...

लेकिन आपके साथ .first()गलत व्यवहार होगा:

var x = Rx.Observable.interval(1000)
  .do( x=> console.log("One"))
  .first()
  .switchMap(x => Rx.Observable.interval(1000))
  .do( x=> console.log("Two"))
  .subscribe((x) => {})

// In console you will see:
// One
// One
// Two
// One
// Two
// One
// etc... 

यहाँ पर कोडपेन का लिंक दिया गया है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.