การใช้ EventEmitter ที่เหมาะสมคืออะไร


225

ฉันได้อ่านคำถามเช่นAccess EventEmitter Service ภายใน CustomHttp ซึ่งผู้ใช้ใช้ EventEmitter ในบริการของเขา แต่เขาแนะนำในความคิดเห็นนี้ว่า อย่าใช้และใช้แทน Observables โดยตรงในบริการของเขา

ฉันยังอ่านคำถามนี้ ซึ่งโซลูชันแนะนำให้ส่ง EventEmitter ไปยังเด็กและสมัครเป็นสมาชิก

คำถามของฉันคือ: ฉันควรหรือไม่ควรสมัครสมาชิกด้วยตนเองกับ EventEmitter? ฉันจะใช้มันได้อย่างไร


2
สำเนาซ้ำที่เป็นไปได้ของการมอบหมาย: EventEmitter หรือ Observable ใน Angular2
GünterZöchbauer

2
คำตอบที่ดีจากมาร์คตามปกติ แต่จริงๆแล้วเขาไม่ได้อธิบายว่าทำไมฉันจึงอธิบาย ฉันไม่ได้ต่อต้านการปิดมัน แต่ฉันต้องการความคิดเห็นของเขาก่อน @MarkRajcok ความคิด?
Eric Martinez

ฉันต้องการเปิดใจต่อไปนี้ (และฉันแน่ใจว่าฉันจะชี้ผู้คนที่นี่ - ฉันเพิ่งแก้ไขคำตอบอื่น ๆ ของฉันให้ชี้ที่นี่!) คำตอบของคุณมีข้อมูลเพิ่มเติมเล็กน้อย ฉันต้องการชื่อคำถามสองข้อ แต่ ... อีกข้อคือ "การใช้ EventEmitter ที่เหมาะสมคืออะไร"
Mark Rajcok

@ MarkRajcok ฉันชอบชื่อนั้น แต่มันไม่เหมาะกับคำตอบปัจจุบันดังนั้นฉันจะทำให้แน่ใจว่าได้อัปเดตในภายหลังเพิ่มตัวอย่างของวิธีการใช้งานและวิธีการที่ไม่เหมาะสม ขอบคุณสำหรับคำติชมของคุณ :)
Eric Martinez

@MarkRajcok แก้ไขตามที่แนะนำ (y), (คัดลอกและวางชื่อที่แนะนำเครดิตทั้งหมดให้คุณ)
Eric Martinez

คำตอบ:


342

TL; DR :

ไม่ไม่ต้องสมัครสมาชิกด้วยตนเองอย่าใช้พวกเขาในบริการ ใช้พวกเขาตามที่แสดงในเอกสารประกอบเท่านั้นเพื่อส่งเหตุการณ์ในส่วนประกอบ อย่ากำจัดสิ่งที่เป็นนามธรรมของเชิงมุม

ตอบ:

ไม่คุณไม่ควรสมัครด้วยตนเอง

EventEmitterเป็นนามธรรมเชิงมุม 2 และจุดประสงค์เพียงอย่างเดียวของมันคือการปล่อยกิจกรรมในส่วนประกอบ การอ้างอิงความคิดเห็นจาก Rob Wormald

[... ] EventEmitter เป็นแองกูลาร์นามธรรมที่เป็นนามธรรมและควรใช้สำหรับการเปล่งเหตุการณ์ที่กำหนดเองในส่วนประกอบเท่านั้น มิฉะนั้นเพียงแค่ใช้ Rx ราวกับว่ามันเป็นห้องสมุดอื่น ๆ

สิ่งนี้ระบุไว้ชัดเจนในเอกสารของ EventEmitter

ใช้ตามคำสั่งและส่วนประกอบเพื่อปล่อยเหตุการณ์ที่กำหนดเอง

มีอะไรผิดปกติเกี่ยวกับการใช้มัน?

Angular2 จะไม่รับประกันว่า EventEmitter จะยังคงเป็น Observable ต่อไป นั่นหมายความว่าการเปลี่ยนรหัสของเราหากมันเปลี่ยน API เดียวที่เราต้องเข้าถึงคือemit()วิธีการ เราไม่ควรสมัครสมาชิกด้วย EventEmitter ด้วยตนเอง

ทั้งหมดที่ระบุไว้ข้างต้นมีความชัดเจนมากขึ้นในความคิดเห็นของ Ward Bell นี้(แนะนำให้อ่านบทความและคำตอบสำหรับความคิดเห็นนั้น) ข้อความอ้างอิงสำหรับการอ้างอิง

อย่าพึ่งพา EventEmitter ต่อไปเพื่อให้เป็น Observable!

อย่าวางใจในโอเปอเรเตอร์ที่สังเกตการณ์เหล่านั้นได้ในอนาคต!

เหล่านี้จะถูกเลิกใช้ในไม่ช้าและอาจถูกลบออกก่อนที่จะเผยแพร่

ใช้ EventEmitter สำหรับการผูกเหตุการณ์ระหว่างลูกและองค์ประกอบหลักเท่านั้น อย่าสมัครเป็นสมาชิก อย่าเรียกวิธีการใด ๆ เหล่านั้น โทรเท่านั้นeve.emit()

ความคิดเห็นของเขาสอดคล้องกับความคิดเห็นของ Rob นานมาแล้ว

ดังนั้นวิธีการใช้อย่างถูกต้อง?

เพียงแค่ใช้มันเพื่อส่งเหตุการณ์จากส่วนประกอบของคุณ ลองดูตัวอย่างต่อไปนี้

@Component({
    selector : 'child',
    template : `
        <button (click)="sendNotification()">Notify my parent!</button>
    `
})
class Child {
    @Output() notifyParent: EventEmitter<any> = new EventEmitter();
    sendNotification() {
        this.notifyParent.emit('Some value to send to the parent');
    }
}

@Component({
    selector : 'parent',
    template : `
        <child (notifyParent)="getNotification($event)"></child>
    `
})
class Parent {
    getNotification(evt) {
        // Do something with the notification (evt) sent by the child!
    }
}

วิธีที่จะไม่ใช้มัน?

class MyService {
    @Output() myServiceEvent : EventEmitter<any> = new EventEmitter();
}

หยุดตรงนั้น ... คุณผิดแล้ว ...

หวังว่าตัวอย่างง่ายๆสองตัวอย่างนี้จะอธิบายการใช้งานที่เหมาะสมของ EventEmitter


1
คุณหมายถึงอะไร: directives : [Child]ในคำนิยามองค์ประกอบ นี่ดูเหมือนจะไม่ได้รวบรวมและฉันไม่สามารถหาได้อธิบายไว้ในเอกสารประกอบ Angular2
themathmagician

1
@Eric: วิธีที่จะไม่ใช้ในตัวอย่างของคุณชัดเจนมากทำไมเราต้องใช้มัณฑนากร '@Output' ในบริการ
trungk18

1
@themathmagician หลังจากบิตของการวิจัยผมพบว่าที่นี่ว่าdirectivesคำหลักที่ได้ถูกเลิกใช้ ใช้declarationsคำหลัก@NgModuleตามที่กำหนดไว้ที่นี่หรือที่นี่
cjsimon

5
ความคิดเห็นใด ๆ เกี่ยวกับคำตอบล่าสุดของ Toby? ฉันเดาว่าคำตอบของเขาควรเป็นคำตอบที่ได้รับในทุกวันนี้
Arjan

7
@Eric เมื่อคุณเขียนคำตอบนี้คุณเขียนว่า: 'สิ่งเหล่านี้จะถูกคัดค้านในไม่ช้าและอาจถูกลบออกก่อนที่จะเผยแพร่' ให้อ้างถึง Ward Bell แต่นี่ถูกระบุ 2 ปีที่แล้วและตอนนี้เรามี angular6 คำสั่งนี้ใช้ยังอยู่ตอนนี้หรือไม่? ฉันยังคงเห็นในเอกสารอย่างเป็นทางการว่า EventEmitter ยังคงมีวิธีการสมัคร () ดังนั้นฉันคิดว่าถ้า Google ต้องการหยุดใช้ EE ในวิชา Rxjs พวกเขาจะทำมันแล้ว คุณคิดว่าคำตอบดั้งเดิมของคุณยังเหมาะสมกับสถานะปัจจุบันของ Angular หรือไม่
Nad G

101

ใช่ไปข้างหน้าและใช้งาน

EventEmitterเป็นสาธารณะประเภทเอกสารใน Angular Core API ขั้นสุดท้าย ไม่ว่าจะมีพื้นฐานมาจากหรือไม่นั้นObservableไม่เกี่ยวข้อง หากเอกสารemitและsubscribeวิธีการของมันเหมาะสมกับสิ่งที่คุณต้องการแล้วไปข้างหน้าและใช้มัน

ตามที่ระบุไว้ในเอกสาร:

ใช้ Rx.Observable แต่ให้อะแดปเตอร์เพื่อให้ทำงานตามที่ระบุไว้ที่นี่: https://github.com/jhusain/observable-spec

เมื่อมีการใช้งานอ้างอิงของข้อมูลจำเพาะให้สลับไปใช้

ดังนั้นพวกเขาจึงต้องการObservableวัตถุที่คล้ายกันซึ่งมีพฤติกรรมบางอย่างพวกเขานำมันมาใช้และทำให้เป็นสาธารณะ ถ้ามันเป็นเพียงสิ่งที่เป็นนามธรรมเชิงมุมภายในที่ไม่ควรใช้พวกเขาจะไม่ทำให้มันเป็นที่เปิดเผย

มีหลายครั้งที่การใช้ตัวปล่อยความร้อนซึ่งส่งเหตุการณ์ประเภทเฉพาะมีประโยชน์มากมาย หากเป็นกรณีการใช้งานของคุณไปได้เลย หาก / เมื่อมีการใช้งานอ้างอิงของข้อมูลจำเพาะที่ลิงก์เชื่อมโยงพร้อมใช้งานควรเป็นการแทนที่แบบดรอปอินเช่นเดียวกับโพลีฟิลอื่น ๆ

เพียงแค่ให้แน่ใจว่าเครื่องกำเนิดที่คุณส่งไปยังsubscribe()ฟังก์ชั่นเป็นไปตามข้อกำหนดที่เชื่อมโยง วัตถุที่ถูกส่งคืนนั้นรับประกันว่าจะมีunsubscribeวิธีการที่ควรเรียกว่าให้ทำการอ้างอิงใด ๆ กับตัวสร้าง (ขณะนี้เป็นวัตถุRxJsSubscriptionแต่นั่นเป็นรายละเอียดการใช้งานจริงซึ่งไม่ควรขึ้นอยู่กับ)

export class MyServiceEvent {
    message: string;
    eventId: number;
}

export class MyService {
    public onChange: EventEmitter<MyServiceEvent> = new EventEmitter<MyServiceEvent>();

    public doSomething(message: string) {
        // do something, then...
        this.onChange.emit({message: message, eventId: 42});
    }
}

export class MyConsumer {
    private _serviceSubscription;

    constructor(private service: MyService) {
        this._serviceSubscription = this.service.onChange.subscribe({
            next: (event: MyServiceEvent) => {
                console.log(`Received message #${event.eventId}: ${event.message}`);
            }
        })
    }

    public consume() {
        // do some stuff, then later...

        this.cleanup();
    }

    private cleanup() {
        this._serviceSubscription.unsubscribe();
    }
}

การคาดการณ์ลงโทษและคำพยากรณ์ที่ดูถูกทั้งหมดดูเหมือนจะเกิดจากความคิดเห็น Stack Overflow เดียวจากผู้พัฒนารายเดียวใน Angular 2 รุ่นก่อนวางจำหน่าย


2
ฟังดูสมเหตุสมผล - มีคนอื่นอยากชั่งน้ำหนักสิ่งนี้หรือไม่? สมัครสมาชิกเป็นวิธีการสาธารณะในเหตุการณ์อีซีแอลหลังจากทั้งหมดหรือไม่
Shawson

ตกลงเป็นสาธารณะดังนั้นเรามีอิสระที่จะใช้ แต่มีเหตุผลเชิงปฏิบัติใด ๆ ที่จะใช้ EventEmitter มากกว่า Observable ในตัวอย่างนี้?
Botis

6
ตอนนี้เราอยู่ใน Angular v6 และ EventEmmiter ไม่ได้ถูกคัดค้านหรือลบออกดังนั้นฉันจึงบอกว่าปลอดภัยที่จะใช้ อย่างไรก็ตามฉันเห็นประโยชน์ในการเรียนรู้วิธีการใช้สิ่งที่สังเกตได้จาก RxJS
David Meza

ฉันเห็นว่าเป็น "หากคุณใช้ EventEmitter นอก @Output ไม่จำเป็นต้องรีบเปลี่ยนเป็นอย่างอื่นเนื่องจาก api นั้นเสถียรสำหรับ ATM"; หากคุณมีเวลาหรือการหยุดพัก api คุณจะต้องเปลี่ยนมัน (แต่โปรดจำไว้ว่าการที่แองกูลาร์จะเปลี่ยน API สาธารณะที่มีเสถียรภาพ (ไม่ปล่อยและสมัครสมาชิก) นั้นไม่ใช่เรื่องปกติ) นอกจากนี้ยังติดอยู่กับประชาชน API ไม่วิธีการไม่เข้าถึงเรื่องหรือสังเกตที่ไม่ได้กำหนดไว้ใน EventEmitter จะอยู่ทางด้านความปลอดภัย
acidghost

1
ข้อสันนิษฐานว่าบางสิ่งบางอย่างมีความปลอดภัยที่จะใช้เพราะ "ไม่ถูกลบออกจาก Angular" หรือ "เอกสารที่ดี" นั้นไม่ถูกต้องเช่นเดียวกับนโยบาย nono ที่เสนอข้างต้น คุณสร้างโครงการไม่ใช่เพื่อเหตุผลของเวอร์ชันเชิงมุมในอนาคต มีหลายแพลตฟอร์มที่ไม่ถูกทิ้งไว้ข้างนอกที่ยังคงทำงานบนเว็บ เวอร์ชันของเฟรมเวิร์กไม่ได้ทำให้นักพัฒนาซอฟต์แวร์ที่ทำงานบนแพลตฟอร์มเหล่านั้นน้อยนักพัฒนาหรือผู้พัฒนาหมวด B
Claudio Ferraro

4

เมื่อคุณต้องการมีปฏิสัมพันธ์ข้ามองค์ประกอบคุณจะต้องรู้ว่าอะไรคือ @Input, @Output, EventEmitter และหัวเรื่อง

ถ้าความสัมพันธ์ระหว่างส่วนประกอบคือ parent หรือ child ในทางกลับกันเราจะใช้ @input & @output กับตัวปล่อยเหตุการณ์

@output ส่งเสียงเหตุการณ์และคุณต้องเปล่งโดยใช้ตัวปล่อยเหตุการณ์

หากไม่ใช่ความสัมพันธ์ของผู้ปกครองเด็ก .. คุณต้องใช้วิชาหรือผ่านบริการทั่วไป


0

ไม่ใช่: ไม่ใช่และไม่ใช่: ใช่ ความจริงอยู่ตรงกลางและไม่มีเหตุผลที่จะต้องกลัวเพราะรุ่นต่อไปของ Angular

จากมุมมองแบบลอจิคัลหากคุณมีชิ้นส่วนและคุณต้องการแจ้งให้ส่วนประกอบอื่น ๆ ว่ามีบางอย่างเกิดขึ้นเหตุการณ์ควรจะถูกไล่ออกและสิ่งนี้สามารถทำได้ในแบบที่คุณคิดว่าควรจะทำ ฉันไม่เห็นเหตุผลที่จะไม่ใช้และฉันไม่เห็นเหตุผลที่จะใช้มันในทุกค่าใช้จ่าย นอกจากนี้ชื่อ EventEmitter แนะนำให้ฉันเหตุการณ์ที่เกิดขึ้น ฉันมักจะใช้มันสำหรับเหตุการณ์สำคัญที่เกิดขึ้นในองค์ประกอบ ฉันสร้างบริการ แต่สร้างไฟล์บริการภายในโฟลเดอร์คอมโพเนนต์ ดังนั้นไฟล์บริการของฉันจะกลายเป็นประเภทของตัวจัดการเหตุการณ์หรืออินเทอร์เฟซเหตุการณ์ดังนั้นฉันสามารถคิดได้อย่างรวดเร็วว่าเหตุการณ์ใดที่ฉันสามารถสมัครสมาชิกกับองค์ประกอบปัจจุบัน

ฉันรู้ .. บางทีฉันเป็นนักพัฒนาที่เก่าไปหน่อย แต่นี่ไม่ใช่ส่วนหนึ่งของรูปแบบการพัฒนาที่ขับเคลื่อนด้วยเหตุการณ์นี่เป็นส่วนหนึ่งของการตัดสินใจสถาปัตยกรรมซอฟต์แวร์ของโครงการเฉพาะของคุณ

ผู้ชายบางคนอาจคิดว่าการใช้งาน Observables โดยตรงนั้นยอดเยี่ยม ในกรณีดังกล่าวไปข้างหน้าด้วย Observables โดยตรง คุณไม่ใช่ฆาตกรต่อเนื่องที่ทำสิ่งนี้ จนกว่าคุณจะเป็นนักพัฒนาโรคจิตโปรแกรมก็ใช้งานได้แล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.