>웹 프론트엔드 >JS 튜토리얼 >AngularJS_AngularJS의 통신 메커니즘에 대한 자세한 설명

AngularJS_AngularJS의 통신 메커니즘에 대한 자세한 설명

WBOY
WBOY원래의
2016-05-16 15:54:09989검색

지금 전 세계 거의 모든 사람들이 묻고 있습니다! USS AngularJS입니다. 문제가 발생했습니다. 우리 서비스는 Klingon을 사용하지만 컨트롤러는 Ferengi 명령 통신과 통신할 수 없습니다!

AngularJS에서 구성 요소가 통신하는 가장 좋은 방법이 무엇인지에 대해 이 질문을 몇 번이나 받았는지 말할 수 없습니다. 많은 경우 $rootScope 객체를 사용하여 듣고 싶어하는 사람에게 다가가는 것이었습니다. . 메시지를 브로드캐스트하는 것은 실제로는 최선의 방법이 아닙니다. 구성 요소 간에 메시지를 브로드캐스팅한다는 것은 다른 구성 요소의 인코딩에 대한 세부 정보를 알아야 하므로 모듈화 및 재사용이 제한된다는 의미입니다.

이 기사에서는 AngularJS에서 내부 구성 요소 통신을 위해 게시/구독 패턴을 사용하는 방법을 보여 드리겠습니다.


AngularJS에는 구성 요소 간 통신에 사용할 수 있는 여러 가지 방법이 있지만 가장 일반적으로 사용되는 방법에서는 해당 구성 요소가 통신하는 방법에 대해 너무 많은 세부 정보를 알아야 하므로 구성 요소 간의 결합이 증가하고 모듈성과 응집력이 감소하므로 재사용이 어렵습니다. 다른 애플리케이션에 구성요소를 추가하세요.

게시/구독 디자인 패턴을 사용하면 구성 요소 간의 결합을 줄이고 통신 세부 사항을 캡슐화할 수 있습니다. 이는 구성 요소의 모듈성, 테스트 가능성 및 신뢰성을 높이는 데 도움이 됩니다.

내가 설명할 게시/구독 패턴 구현은 @eburley의 Eric Burley가 자신의 게시물 angularjs.org Observations, About the 게시/구독 패턴.. 에서 권장한 것입니다.

제가 설명한 샘플 애플리케이션은 내부 컨트롤러 통신 및 컨트롤러 서비스 통신에 게시/구독 패턴을 사용하는 방법을 보여줍니다. GitHub angularjs- pubsub 소스 찾기에서 찾을 수 있습니다. 아래 코드를 입력하세요.

먼저 소통채널이 필요합니다

먼저 게시 및 구독 정보를 처리하는 데 사용되는 서비스에 대해 이야기하겠습니다. 나는 교환하려는 정보를 처리하는 데 사용할 수 있는 정보 게시 및 구독 방법을 제공하는 서비스 인터페이스를 정의했습니다.

아래 코드에서는 두 개의 내부 메시지를 정의합니다. _EDIT_DATA_는 메시지와 함께 전달된 데이터를 편집해야 함을 나타내고, _DATA_UPDATED_는 데이터가 변경되었음을 나타냅니다. 이는 내부적으로 정의되며 사용자가 액세스할 수 없으므로 구현을 숨기는 데 도움이 됩니다.

각 정보에는 두 가지 방법이 있습니다. 하나는 정보를 게시하고 구독자에게 푸시하는 데 사용되며, 다른 하나는 구독자가 정보를 수신할 때 호출되는 콜백 메소드를 등록하는 데 사용됩니다.


구독자에게 정보를 게시하는 데 사용되는 메서드는 9행의 editData 및 19행의 dataUpated입니다. $rootScope.$broadcast 메소드를 통해 보류 중인 이벤트에 개인 알림을 푸시합니다.

이벤트를 등록하는 방법은 $scope.$on을 통해 리스너를 설정하는 것입니다. 브로드캐스트 메시지를 수신한 후 구독자가 서비스에 등록한 이벤트가 차례로 실행됩니다. 동시에 구독자는 자신의 범위를 매개변수로 전달해야 하므로 이를 사용하여 모니터링된 정보를 실행할 수 있으므로 리스너 목록을 유지하는 복잡한 처리를 피할 수 있습니다. 이벤트를 등록하는 메소드는 13행의 onEditData, 23행의 onDataUpdated입니다.

구현 세부 사항을 숨기기 위해 Revealing Module(공개 모듈: 보기 흉한 이름) 패턴을 사용하여 사용자가 사용하기를 원하는 메소드만 반환했습니다.

angular.module(['application.services'])
  // define the request notification channel for the pub/sub service
  .factory('requestNotificationChannel', ['$rootScope', function ($rootScope) {
    // private notification messages
    var _EDIT_DATA_ = '_EDIT_DATA_';
    var _DATA_UPDATED_ = '_DATA_UPDATED_';
 
    // publish edit data notification
    var editData = function (item) {
      $rootScope.$broadcast(_EDIT_DATA_, {item: item});
    };
    //subscribe to edit data notification
    var onEditData = function($scope, handler) {
      $scope.$on(_EDIT_DATA_, function(event, args) {
        handler(args.item);
      });
    };
    // publish data changed notification
    var dataUpdated = function () {
      $rootScope.$broadcast(_DATA_UPDATED_);
    };
    // subscribe to data changed notification
    var onDataUpdated = function ($scope, handler) {
      $scope.$on(_DATA_UPDATED_, function (event) {
        handler();
      });
    };
    // return the publicly accessible methods
    return {
      editData: editData,
      onEditData: onEditData,
      dataUpdated: dataUpdated,
      onDataUpdated: onDataUpdated
    };
  }])

메시지 게시

메시지 게시는 간단합니다. 먼저 컨트롤러에 requestNotificationChannel에 대한 몇 가지 종속성을 도입해야 합니다. 이벤트가 발생하면 어떤 변경 사항이 있는지 알아야 하는 경우 아래의 dataService 정의에서 이를 확인할 수 있습니다. 다른 객체에 신호를 보내려면 requestNotificationChannel에서 적절한 알림 메서드만 호출하면 됩니다. dataService의 saveHop, deleteHop 및 addHop 메서드를 보면 모두 requestNotificationChannel에서 dataUpdated 메서드를 호출하는 것을 볼 수 있습니다. onDataUpdated 메소드를 사용하여 등록된 리스너에게 신호가 전송됩니다.

  // define the data service that manages the data
  .factory('dataService', ['requestNotificationChannel', function (requestNotificationChannel) {
    // private data
    var hops = [
      { "_id": { "$oid": "50ae677361d118e3646d7d6c"}, "Name": "Admiral", "Origin": "United Kingdom", "Alpha": 14.75, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Bittering hops derived from Wye Challenger. Good high-alpha bittering hops. Use for: Ales Aroma: Primarily for bittering Substitutions: Target, Northdown, Challenger", "Type": "Bittering", "Form": "Pellet", "Beta": 5.6, "HSI": 15.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6d"}, "Name": "Ahtanum", "Origin": "U.S.", "Alpha": 6.0, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Distinctive aromatic hops with moderate bittering power from Washington. Use for: Distinctive aroma Substitutes: N/A", "Type": "Aroma", "Form": "Pellet", "Beta": 5.25, "HSI": 30.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6e"}, "Name": "Amarillo Gold", "Origin": "U.S.", "Alpha": 8.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Unknown origin, but character similar to Cascade. Use for: IPAs, Ales Aroma: Citrus, Flowery Substitutions: Cascade, Centennial", "Type": "Aroma", "Form": "Pellet", "Beta": 6.0, "HSI": 25.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d6f"}, "Name": "Aquila", "Origin": "U.S.", "Alpha": 6.5, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": "Aroma hops developed in 1988. Limited use due to high cohumolone.Used for: Aroma hops Substitutes: ClusterNo longer commercially grown.", "Type": "Aroma", "Form": "Pellet", "Beta": 3.0, "HSI": 35.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
      { "_id": { "$oid": "50ae677361d118e3646d7d70"}, "Name": "Auscha (Saaz)", "Origin": "Czech Republic", "Alpha": 3.3, "Amount": 0.0, "Use": "Boil", "Time": 0.0, "Notes": " Use for: Pilsners and Bohemian style lagers Aroma: Delicate, mild, clean, somewhat floral -- Noble hops Substitute: Tettnanger, LublinExamples: Pulsner Urquell", "Type": "Aroma", "Form": "Pellet", "Beta": 3.5, "HSI": 42.0, "Humulene": 0.0, "Caryophyllene": 0.0, "Cohumulone": 0.0, "Myrcene": 0.0, "Substitutes": ""} ,
    ];
    // sends notification that data has been updated
    var saveHop = function(hop) {
      requestNotificationChannel.dataUpdated();
    };
    // removes the item from the array and sends a notification that data has been updated
    var deleteHop = function(hop) {
      for(var i = 0; i < hops.length; i++) {
        if(hops[i]._id.$oid === hop._id.$oid) {
          hops.splice(i, 1);
          requestNotificationChannel.dataUpdated();
          return;
        }
      };
    };
    // internal function to generate a random number guid generation
    var S4 = function() {
      return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    // generates a guid for adding items to array
    var guid = function () {
     return (S4() + S4() + "-" + S4() + "-4" + S4().substr(0,3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase();
    };
    // function to add a hop to the array and sends a notification that data has been updated
    var addHop = function(hop) {
      hops.id.$oid = guid();
      hops.push(hop);
      requestNotificationChannel.dataUpdated();
    };
    // returns the array of hops
    var getHops = function() {
      return hops;
    };
    // returns a specific hop with the given id
    var getHop = function(id) {
      for(var i = 0; i < hops.length; i++) {
        if(hops[i]._id.$oid === id) {
          return hops[i];
        }
      };
    };
    // return the publicly accessible methods
    return {
      getHops: getHops,
      getHop: getHop,
      saveHop: saveHop,
      deleteHop: deleteHop,
      addHop: addHop
    }
  }]);

 
接收事件通知

从 requestNotificationChannel 接收事件通知也很简单,额外的我们只需要回调处理器来在消息被发送时使用通知来做一些自己的处理. 我们将再次需要添加一些依赖到面向我们的控制器、服务以及指令的 requestNotificationChannel 上, 你可以在下面代码的第二行中看到这些. 接下来我们需要定义一个事件回调处理器来对事件通知做出回应,你可以在下面的第五行代码中看到. 然后我们需要通过调用 onDataUpdated 方法来吧我们的回调处理器注册到requestNotificationChannel,并传入来自控制器和回调处理器的范围, 我们在第9行代码中做了这些事情.

 

  //define the controller for view1
  .controller('view1-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) {
    $scope.hops = dataService.getHops();
 
    var onDataUpdatedHandler = function() {
      $scope.hops = dataService.getHops();
    }
 
    requestNotificationChannel.onDataUpdated($scope, onDataUpdatedHandler);
 
    $scope.onEdit = function(hop) {
      requestNotificationChannel.editData(hop);
    }
 
    $scope.onDelete = function(hop) {
      dataService.deleteHop(hop);
    }
  }]);

用于控制器通信的控制器

我们也可以将 the requestNotificationChannel 用于控制器间的通信. 我们只需要有一个控制器扮演发布者的角色,而另外一个控制器扮演订阅者的角色就行了. 如果你观察到前段代码第11行view1-controller的onEdit方法,你会看到它发送了一个editData消息,消息包含需要使用 requestNotificationChannel 编辑的项.  下面的 view2-controller 从第5行到第9行将它的 onEditDataHandler 用 requestNotificationChannel 进行了注册. 如此无论何时view1-controller一旦发送editData消息,带上要修改的项,view2-controller都会受到editData消息的通知,获得该项并将其更新到它的模型.
 

  //define the controller for view1
  .controller('view2-controller', ['$scope', 'dataService', 'requestNotificationChannel', function($scope, dataService, requestNotificationChannel) {
    $scope.hop = null;
 
    var onEditDataHandler = function(item) {
      $scope.hop = item;
    };
 
    requestNotificationChannel.onEditData($scope, onEditDataHandler);
 
    $scope.onSave = function() {
      dataService.saveHop($scope.hop);
      $scope.hop = null;
    }
 
    $scope.onCancel = function() {
      $scope.hop = null;
    }
  }]);

写一个好的接口文档

有一件事情可能会被忽略,我们在组件间用了通信接口,而这些接口,它们需要一个好的文档来说明应当如何使用。上面的例子中,如果没有文档,用户肯定不会知道 onEditData 会给回调函数传一个待编辑数据。所以当你开始用这个模式,用好的技巧在于,给方法写注释文档,以确保通知服务明确知道发生了什么事情。
总结

好了,我们探讨了如何在你的 AngularJS 应用中使用订阅/发布模式来实现模块间通信。该模式可以让你的模块从内部消息解耦,更便于复用。你甚至可以把模块之间的通信全部替换成订阅/发布模式。尤其当你的服务中有很多异步请求,以及你希望把数据缓存在服务中,从而减少和服务器通信的时候,这种模式相当有效。

我希望这对你有所帮助,你可以在我的 GitHub 仓库 angularjs-pubsub 下找到例子的代码。

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.