$ rootScope $ broadcast เทียบกับ $ scope $ emit


349

ตอนนี้ที่ความแตกต่างระหว่างประสิทธิภาพ$broadcastและ$emitได้รับการกำจัดจะมีเหตุผลใด ๆ จะชอบ$scope.$emitไป$rootScope.$broadcast?

พวกเขาแตกต่างกันใช่

$emit ถูก จำกัด ในลำดับชั้นของขอบเขต (ขึ้นไป) - อาจดีถ้ามันเหมาะกับการออกแบบของคุณ แต่ดูเหมือนว่าฉันจะมีข้อ จำกัด โดยพลการ

$rootScope.$broadcastทำงานในทุกสิ่งที่เลือกที่จะฟังเหตุการณ์ซึ่งเป็นข้อ จำกัด ที่สมเหตุสมผลมากขึ้นในใจของฉัน

ฉันพลาดอะไรไปรึเปล่า?

แก้ไข:

เพื่อชี้แจงในการตอบสนองต่อคำตอบทิศทางของการจัดส่งไม่ใช่ปัญหาที่ฉันตามมา $scope.$emitยื้อเหตุการณ์ขึ้นและ$scope.$broadcast- ลง แต่ทำไมไม่ใช้$rootScope.$broadcastเพื่อเข้าถึงผู้ฟังที่ตั้งใจไว้เสมอไป?


3
toddmotto.com/…มีทุกอย่าง
Divya MV

คำตอบ:


1155

tl; dr (นี่ tl; dr มาจากคำตอบของ@ sp00mด้านล่าง)

$emitยื้อเหตุการณ์ขึ้นไปข้างบน ... $broadcastยื้อเหตุการณ์ลง

คำอธิบายโดยละเอียด

$rootScope.$emitอนุญาตให้$rootScopeผู้ฟังคนอื่น ๆจับเท่านั้น นี่เป็นสิ่งที่ดีเมื่อคุณไม่ต้องการให้ทุกคน$scopeได้รับ ส่วนใหญ่เป็นการสื่อสารระดับสูง คิดว่ามันเป็นผู้ใหญ่พูดคุยกันในห้องเพื่อให้เด็กไม่สามารถได้ยินพวกเขา

$rootScope.$broadcastเป็นวิธีการที่ให้ทุกอย่างได้ยิน นี่จะเท่ากับผู้ปกครองตะโกนว่าอาหารเย็นพร้อมเพื่อให้ทุกคนในบ้านได้ยิน

$scope.$emitคือเมื่อคุณต้องการสิ่งนั้น$scopeและผู้ปกครองทั้งหมดและ$rootScopeเพื่อฟังเหตุการณ์ นี่คือเด็กที่ส่งเสียงหอนให้พ่อแม่ของพวกเขาที่บ้าน (แต่ไม่ใช่ที่ร้านขายของชำที่เด็กคนอื่นได้ยิน)

$scope.$broadcastสำหรับ$scopeตัวเองและลูก ๆ ของมัน นี่คือเด็กที่กระซิบกับสัตว์ยัดไส้เพื่อที่พ่อแม่จะไม่ได้ยิน


3
@NewDev เหตุผลก็คือบ่อยครั้งที่คุณมีการทำซ้ำขอบเขตบนหน้าเว็บ หากคุณมีสองหรือมากกว่าขอบเขตที่แสดงอินสแตนซ์ของข้อมูลที่แตกต่างกัน - เช่นรายการบันทึกผู้ป่วยในหน้าแต่ละรายการมีขอบเขตของตัวเอง - จากนั้นจะไม่สามารถออกอากาศจากรากเหตุการณ์ที่มีไว้สำหรับหนึ่งในนั้น ขอบเขต หลีกเลี่ยงการ$rootScopeออกอากาศหากเป็นไปได้ให้นำมาใช้ซ้ำได้ดีขึ้น
Tim Rogers

4
ไม่มีสิ่งใดที่คุณพูดว่าผิด แต่มีวิธีการทั่วไปที่ $ emit วางเอกสารลงในขอบเขตของลูกและ $ emit จะเพิ่มเอกสารไปยังขอบเขตหลัก ทั้งสองจะทริกเกอร์ผู้ฟังใด ๆ ที่แนบกับขอบเขตปัจจุบัน
Eric

123
ตัวอย่างที่คุณใช้ดีมาก!
Assaf

72
ว้าว! แม้แต่เด็ก ๆ ก็สามารถเข้าใจสิ่งนี้! น่าทึ่ง :)
Navaneeth

3
ตัวอย่างที่สมบูรณ์แบบรักคำอธิบาย
Robin-Hoodie

104

พวกเขาไม่ได้ทำงานเดียวกัน: $emitส่งเหตุการณ์ขึ้นไปตามลำดับชั้นของขอบเขตในขณะที่$broadcastส่งเหตุการณ์ลงไปที่ขอบเขตเด็กทั้งหมด


2
ใช่ฉันสังเกตเห็นว่าในคำถาม (บางทีฉันอาจทำให้ชัดเจนเกี่ยวกับทิศทางของการจัดส่ง) แต่ฉันก็ตั้งข้อสังเกตว่านั่นเป็นข้อ จำกัด โดยพลการ หากฉันสามารถเข้าถึง "ผู้ฟัง" ของฉันได้ทำไมฉันไม่ทำเช่นนี้ลงมาเสมอ$rootScope?
ใหม่ Dev

เนื่องจาก $ emit จะไม่ส่งผลกระทบต่อขอบเขตของลูกหรือขอบเขตพี่น้อง สิ่งเหล่านี้เพียงจับคู่กับประเภทการเผยแพร่เหตุการณ์ของ JavaScript - การจับภาพและเดือดปุด ๆ $ Broadcast ใช้สำหรับการจับภาพและ $ emit ใช้สำหรับการเดือดปุด ๆ ตอนนี้มีบทความ quirksmode โบราณที่ดูเหมือนจะอธิบายความแตกต่างได้ดีมาก: quirksmode.org/js/events_order.html
Alan L.

77

ฉันทำกราฟิกต่อไปนี้จากลิงก์ต่อไปนี้: https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribeing/

ขอบเขต, rootScope, ปล่อย, ออกอากาศ

อย่างที่คุณสามารถเห็นได้รับความ$rootScope.$broadcastนิยมมากกว่าผู้ฟังมากกว่า$scope.$emitฮิตฟังมากขึ้นกว่า

นอกจากนี้ยัง$scope.$emitสามารถยกเลิกเอฟเฟกต์ฟองสบู่ได้ในขณะที่$rootScope.$broadcastไม่สามารถทำได้


24
ฉันเห็นลูกศรจำนวนมาก
Mars Robertson

4
@MichalStefanow ฉันเป็นแฟนของคำตอบภาพ :)
มาเรีย Ines Parnisari

@mparnisari:. $ Broadcast (ชื่อ, args) - ออกอากาศเหตุการณ์ผ่านขอบเขต $ ของเด็กทุกคน $ emit (ชื่อ, args) - ปล่อยเหตุการณ์ขึ้นลำดับ $ scope ให้กับผู้ปกครองทั้งหมดรวมถึง $ rootScope
CodeMan

19

ป้อนคำอธิบายรูปภาพที่นี่

$ scope $ emit: วิธีนี้กระจายเหตุการณ์ในทิศทางขึ้นไป

ป้อนคำอธิบายรูปภาพที่นี่ $ scope $ broadcast: วิธีกระจายเหตุการณ์ในทิศทางลง (จากพาเรนต์สู่ชายด์) ไปยังตัวควบคุมลูกทั้งหมด

ป้อนคำอธิบายรูปภาพที่นี่ $ scope $ on: วิธีการลงทะเบียนเพื่อฟังเหตุการณ์บางอย่าง ตัวควบคุมทั้งหมดที่กำลังฟังเหตุการณ์นั้นได้รับการแจ้งเตือนของการออกอากาศหรือปล่อยออกมาตามตำแหน่งที่เหมาะสมในลำดับชั้นของผู้ปกครองเด็ก

เหตุการณ์ $ emit สามารถถูกยกเลิกได้โดยหนึ่งใน $ scope ที่กำลังฟังเหตุการณ์

$ on จัดเตรียมวิธีการ "stopPropagation" โดยเรียกวิธีนี้เหตุการณ์สามารถหยุดจากการเผยแพร่เพิ่มเติม

ปังเกอร์: https://embed.plnkr.co/0Pdrrtj3GEnMp2UpILp4/

ในกรณีของขอบเขต sibling (ขอบเขตที่ไม่ได้อยู่ในลำดับชั้นของ parent-child โดยตรง) ดังนั้น $ emit และ $ broadcast จะไม่สื่อสารกับขอบเขต sibling

ป้อนคำอธิบายรูปภาพที่นี่

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ http://yogeshtutorials.blogspot.in/2015/12/event-based-communication-between-angularjs-controllers.html


ยินดีต้อนรับลิงก์ไปยังโซลูชัน แต่โปรดตรวจสอบให้แน่ใจว่าคำตอบของคุณมีประโยชน์หากไม่มี: เพิ่มบริบทรอบลิงก์เพื่อให้ผู้ใช้เพื่อนของคุณมีความคิดว่ามันคืออะไรและเพราะเหตุใดจึงอยู่ที่นั่น กำลังเชื่อมโยงไปยังในกรณีที่หน้าเป้าหมายไม่พร้อมใช้งาน คำตอบที่น้อยกว่าลิงก์อาจถูกลบ
Baum mit Augen

วัตถุประสงค์คือเพื่อให้ผู้ทำงานที่พลั่วเกอร์อย่างไรก็ตามฉันได้เพิ่มคำอธิบายที่เหมาะสมที่นี่
Yogesh

3

@Eddie ได้ให้คำตอบที่สมบูรณ์แบบของคำถามที่ถาม แต่ฉันต้องการดึงความสนใจไปที่การใช้วิธีการที่มีประสิทธิภาพมากขึ้นของผับ / ซับ

ในฐานะที่เป็นนี้คำตอบที่แสดงให้เห็น

วิธี $ Broadcast / $ on นั้นไม่มีประสิทธิภาพมากนักเนื่องจากมันแพร่กระจายไปยังขอบเขตทั้งหมด (ทั้งในทิศทางเดียวหรือทั้งสองทิศทางของลำดับชั้นขอบเขต) ในขณะที่วิธี Pub / Sub นั้นตรงกว่ามาก เฉพาะสมาชิกเท่านั้นที่ได้รับเหตุการณ์ดังนั้นมันจะไม่ไปทุกขอบเขตในระบบเพื่อให้มันทำงานได้

คุณสามารถใช้angular-PubSubโมดูลเชิงมุม เมื่อคุณเพิ่มPubSubโมดูลในการพึ่งพาแอปของคุณคุณสามารถใช้PubSubบริการเพื่อสมัครสมาชิกและยกเลิกการสมัครกิจกรรม / หัวข้อ

สมัครง่าย:

// Subscribe to event
var sub = PubSub.subscribe('event-name', function(topic, data){

});

เผยแพร่ได้ง่าย

PubSub.publish('event-name', {
    prop1: value1,
    prop2: value2
});

ต้องการยกเลิกการใช้งานหรือPubSub.unsubscribe(sub);PubSub.unsubscribe('event-name');

หมายเหตุอย่าลืมยกเลิกการสมัครเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำ


2

ใช้ RxJS ในบริการ

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

สร้างบริการที่มีRxJS ส่วนขยายสำหรับเชิงมุม

<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/rx/dist/rx.all.js"></script>
<script src="//unpkg.com/rx-angular/dist/rx.angular.js"></script>
var app = angular.module('myApp', ['rx']);

app.factory("DataService", function(rx) {
  var subject = new rx.Subject(); 
  var data = "Initial";

  return {
      set: function set(d){
        data = d;
        subject.onNext(d);
      },
      get: function get() {
        return data;
      },
      subscribe: function (o) {
         return subject.subscribe(o);
      }
  };
});

จากนั้นก็สมัครรับการเปลี่ยนแปลง

app.controller('displayCtrl', function(DataService) {
  var $ctrl = this;

  $ctrl.data = DataService.get();
  var subscription = DataService.subscribe(function onNext(d) {
      $ctrl.data = d;
  });

  this.$onDestroy = function() {
      subscription.dispose();
  };
});

ลูกค้าสามารถสมัครสมาชิกเพื่อรับกับการเปลี่ยนแปลงและผู้ผลิตสามารถผลักดันการเปลี่ยนแปลงด้วยDataService.subscribeDataService.set

DEMO บน PLNKR

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