简体   繁体   English

AngularJS websockets太快

[英]AngularJS websockets too fast

I am using AngularJS to power my webapp. 我正在使用AngularJS为我的Web应用程序供电。 Recently I've decided to introduce Stomp over websockets in the mix with RabbitMQ. 最近,我决定与RabbitMQ一起在Websockets上引入Stomp。 One problem that I keep hitting is that sometimes the messages sent from the backend are at so high frequency that Angular fails to trigger some events losing data in the process. 我一直遇到的一个问题是,有时后端发送的消息的频率很高,以至于Angular无法触发某些事件,从而导致进程丢失数据。

The application is rather complex so sometimes a message might pass through the following chain 该应用程序相当复杂,因此有时一条消息可能会通过以下链

  1. StompJS Angular service wrapper. StompJS Angular服务包装器。 Uses $rootScope.$broadcast to notify components when new messages have arrived 使用$ rootScope。$ broadcast在新消息到达时通知组件
  2. Controller that registers to messages that are being broadcast on $rootScope. 注册到$ rootScope上正在广播的消息的控制器。 Controller then updates bindings or sends another event to a component to perform some data updates. 然后,控制器更新绑定或将另一个事件发送到组件以执行一些数据更新。

As I mentioned sometimes the scopes don't get updated properly, even though the events are being sent and the values are being populated the view does not show the updated values. 正如我提到的那样,即使发送事件和填充值, 有时也无法正确更新范围,但视图仍未显示更新后的值。 I have used $scope.$apply, $timeout, $scope.$digest and nothing seems to work... For example if I have 2 packets coming one after another and there's little or no delay between them on the socket nothing happens but if there's one the same piece of code functions properly. 我用过$ scope。$ apply,$ timeout,$ scope。$ digest似乎没有任何工作...例如,如果我有2个数据包一个接一个地出现,并且套接字之间几乎没有延迟,或者没有延迟,但是如果有相同的一段代码,则功能正常。 How to overcome this ? 如何克服呢?

To further exemplify after some questions posted by the users: 为了进一步举例说明用户提出的一些问题:

I will take the most simple example: i get progress reports from a job that runs on the backend. 我将以最简单的示例为例:我从后端运行的工作获取进度报告。 Basically it tells me how many rows have been written in a Cassandra database. 基本上,它告诉我在Cassandra数据库中已经写了多少行。 So I get notifications like {wrote: 8000, total: 4000000}. 因此,我收到诸如{写信:8000,总数:4000000}之类的通知。 "wrote" is being increased as the workers write in the database and since there are multiple workers sometimes these notifications get pushed very fast. 随着工作人员在数据库中的写入,“写”正在增加,并且由于有多个工作人员,有时这些通知会很快推送。 I have a custom grid component written that listens for events like grid:updateCell (which allows me to update a cell with the progress report). 我编写了一个自定义的网格组件,用于侦听grid:updateCell之类的事件(这使我可以使用进度报告来更新单元格)。 Every time a packet comes on the socket I broadcast that event ($scope.$broadcast because the grid it is a child of page the controller). 每当套接字上有数据包时,我都会广播该事件($ scope。$ broadcast,因为网格是控制器页面的子级)。 I have noticed that not all the updates from the socket get reflected in the UI although the event is caught and the grid event is also triggered with successful update of the data model but the not the UI 我注意到,虽然捕获了事件,但并非所有来自套接字的更新都反映在UI中,并且成功更新数据模型也触发了Grid事件,但不是UI

It seems to me you might have a few things going on here. 在我看来,您可能在这里发生了一些事情。

1) Using $scope.$broadcast bubbles down the scope which could be quite heavy if you have lots of nested scopes. 1)使用$ scope。$ broadcast缩小范围,如果您有很多嵌套的范围,可能会很沉重。 I prefer to attach event listeners to the $rootScope and use $emit which only broadcast to the current scope and is quicker. 我更喜欢将事件侦听器附加到$ rootScope并使用$ emit,它只广播到当前作用域,并且速度更快。 I have the below service for this 我为此提供以下服务

    /**
     * @ngdoc service
     * @name someModule.eventbus
     * @requires $rootScope
     *
     * @description
     * Provides a eventing mechanism when a user cna broadcast and subscribe to application wide events.
     */
    angular.module('someModule').factory('eventbus', [
        '$rootScope',
        function ($rootScope) {
            /**
             * @ngdoc function
             * @name subscribe
             * @methodOf someModule.eventbus
             *
             * @description
             * Subscribes a callback to the given application wide event
             *
             * @param {String} eventName The name of the event to subscribe to.
             * @param {Function} callback A callback which is fire when the event is raised.
             * @return {Function} A function tht can be called to unsubscrive to the event.
             */
            var subscribe = function (eventName, callback) {
                    return $rootScope.$on(eventName, callback);
                },

                /**
                 * @ngdoc function
                 * @name broadcast
                 * @methodOf someModule.eventbus
                 *
                 * @description
                 * Broadcasts the given event and data.
                 *
                 * @param {String} eventName The name of the event to broadcast.
                 * @param {object} data A data object that will be passed along with the event.
                 */
                broadcast = function (eventName, data) {
                    $rootScope.$emit(eventName, data);
                };

            return {
                subscribe: subscribe,
                broadcast: broadcast
            };
        }
    ]);
  1. You might not be firing the update within an Angular digest cycle which would explain why you are only getting some updates. 您可能没有在Angular摘要周期内触发更新,这可以解释为什么只得到一些更新。 Try doing the update with a digest cycle (put the function within a $timeout block which is the recommended way over $scope.$apply 尝试使用摘要循环进行更新(将功能放入$ timeout块中,这是在$ scope上的推荐方式。

    $timeout(function () { doUpdate(dataFromMessageBus); }); $ timeout(function(){doUpdate(dataFromMessageBus);});

  2. If you get alot of messages you should use a debounce function see lodash-debouce . 如果收到大量消息,则应使用反跳功能,请参阅lodash-debouce A person can only really process in circa 200ms chunks so generally updating every 200ms will be the most someone can take in. I would personally do it every second or so in say a trading app etc. 一个人只能真正处理大约200毫秒的块,因此通常每200毫秒进行更新将是某人可以接受的最多。我个人大约每秒进行一次处理,例如交易应用程序等。

(using lodash - debounce) (使用lodash-反跳)

function (messageBus) {
  var debounceFn = _.debounce(function () {
      $timeout(function() {
        doUpdate(data);
      });
    }, 1000);

    // just assuming here about your socket / message bus stuff
    messageBus.onMessageRecieved(function () {
      //Call debounce function which will only actually call the inner func every 1000ms
      debounceFn();
   });

}

I had the same issue before and I was able to solve it by wrapping the websocket incoming message handler which updates my Angular Grid in the following: 我之前遇到过同样的问题,我可以通过包装websocket传入消息处理程序来解决此问题,该处理程序将在下面更新我的Angular Grid:

$scope.$apply(function () {

//your code to update the Angular UI

});

Example: 例:

    /**
     * @ngdoc function
     * @description
     * On Connect. Callback to subscribe to specific socket destination. 
     */
    function _subscribeBcQueue(){
        var uuid = SessionService.getUuid();
        var userBcQueue = CONFIG.SOCKET.bcQueue+'/'+uuid
        var subscription = $stomp.subscribe(userBcQueue, function (payload, headers, message) {
            _onBcMessageHandler(message)
        }, {})
    }

    /**
     * @ngdoc function
     * @description
     * OnBcMessageHandler. Callback function to handle the incoming direct message. 
     */
    function _onBcMessageHandler(message){
        //TODO Process the broadcasting status message
        var bcMsg = JSON.parse(message.body);
        console.log("Broadcasting status message:" + bcMsg);
        _updateBcJobGridRow(bcMsg)
    }



    function _updateBcJobGridRow(job) {
            $scope.$apply(function () {
                //Get the old JobGridRow 
                console.log("jobId: " + JSON.stringify(job.id));
                var oldJobGridRow = $filter('filter')(vm.gridOptions.data, {id: job.id})[0];
                console.log("oldJobGridRow: " + JSON.stringify(oldJobGridRow));
                if (oldJobGridRow) {
                    var newJobGridRow = _getBcJobGridRow(job);
                    console.log("newJobGridRow: " + JSON.stringify(newJobGridRow));
                    oldJobGridRow.progress = newJobGridRow.progress;
                    oldJobGridRow.percentage = newJobGridRow.percentage;
                    oldJobGridRow.status = newJobGridRow.status;
                    oldJobGridRow.total = newJobGridRow.total;
                    oldJobGridRow.sent = newJobGridRow.sent;
                    oldJobGridRow.recipients = newJobGridRow.recipients;
                }
            });
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM