<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 9. actioncable 實現重新連接功能 #### 1. 介紹 當我們在一個網頁聊天室聊天的時候,我們有一個情況,會顯示是在線,還是離線狀態,還有,有一些網頁型的項目管理工具,在離線狀態的時候,可能是網絡連不上的時候,也能夠進行操作,不過它是把數據暫時保存到瀏覽器本地,等網絡通了,就會自動同步到服務器中,這些又是如何辦到的呢,這篇文章就來講這個原理。 ![](https://box.kancloud.cn/8478918b4ffab89229d2611a6509656b_399x248.png) #### 2. 使用 其實要實現整個功能,我只是用了幾行代碼,不過最重要的是理解了actioncable中的javascript部分源碼,通過復寫其中的方法來實現的。 現在就來看看這部分的源碼。 ##### 2.1 cable.coffee 我們先從項目中的入口文件`app/assets/javascripts/cable.coffee`看起,其內容大約是這樣的: ``` @App ||= {} App.cable = ActionCable.createConsumer() ``` 相關的源碼是這樣的: ``` # https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/actioncable/app/assets/javascripts/action_cable.coffee.erb#L4 @ActionCable = INTERNAL: <%= ActionCable::INTERNAL.to_json %> createConsumer: (url) -> url ?= @getConfig("url") ? @INTERNAL.default_mount_path new ActionCable.Consumer @createWebSocketURL(url) ``` ##### 2.2 ActionCable.createConsumer 這個`ActionCable.createConsumer`方法我們之前也有講過,它就是通過一些參數,找到就正確的服務器地址,然后執行`new WebSocket`的。 而且你還在源碼文件`action_cable.coffee.erb`中看到下面幾行。 ``` startDebugging: -> @debugging = true stopDebugging: -> @debugging = null log: (messages...) -> if @debugging messages.push(Date.now()) console.log("[ActionCable]", messages...) ``` `@debugging`變量是開啟日志的開關,我們把它設為true。 ``` # app/assets/javascripts/cable.coffee @App ||= {} App.cable = ActionCable.createConsumer() ActionCable.startDebugging() ``` 現在我們就可以在chrome等瀏覽器的開發者工具的console標簽看到更為詳盡的日志內容了。 ![](https://box.kancloud.cn/aac2596c43ee48a381c687c7ceddbcd7_974x205.png) ##### 2.3 ActionCable.Consumer 現在來看一下`new ActionCable.Consumer`的內容: ``` # https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/actioncable/app/assets/javascripts/action_cable/consumer.coffee#L17 class ActionCable.Consumer constructor: (@url) -> @subscriptions = new ActionCable.Subscriptions this @connection = new ActionCable.Connection this send: (data) -> @connection.send(data) ensureActiveConnection: -> unless @connection.isActive() @connection.open() ``` 很早之前我們就介紹過,如何用javascript給后臺發送websocket請求。 首先是使用`new WebSocket`發起連接指令。 然后使用`send`命令發送具體的消息給后臺,比如`ws.send("Hello");`。 上面的源碼中,`new ActionCable.Connection this`管的就是`new WebSocket`類似的內容。當然它除了有open方法,還有close方法用于關閉連接,reopen方法用于重連。 `new ActionCable.Subscriptions this`的內容主要就是管理如何向服務器端發送具體的消息的,這部分我們先不管。 ##### 2.4 ActionCable.Connection 我們來看看`ActionCable.Connection`相關的內容。 關于它的內容主要是下面兩個文件: - connection.coffee - connection\_monitor.coffee `connection.coffee`文件主要是記錄了open、close,reopen方法,還有連接的活動狀態等。最重要的是reopen方法。 ``` class ActionCable.Connection @reopenDelay: 500 constructor: (@consumer) -> {@subscriptions} = @consumer @monitor = new ActionCable.ConnectionMonitor this @disconnected = true send: (data) -> if @isOpen() @webSocket.send(JSON.stringify(data)) true else false open: => if @isActive() ActionCable.log("Attempted to open WebSocket, but existing socket is #{@getState()}") throw new Error("Existing connection must be closed before opening") else ActionCable.log("Opening WebSocket, current state is #{@getState()}, subprotocols: #{protocols}") @uninstallEventHandlers() if @webSocket? @webSocket = new WebSocket(@consumer.url, protocols) @installEventHandlers() @monitor.start() true close: ({allowReconnect} = {allowReconnect: true}) -> @monitor.stop() unless allowReconnect @webSocket?.close() if @isActive() reopen: -> ActionCable.log("Reopening WebSocket, current state is #{@getState()}") if @isActive() try @close() catch error ActionCable.log("Failed to reopen WebSocket", error) finally ActionCable.log("Reopening WebSocket in #{@constructor.reopenDelay}ms") setTimeout(@open, @constructor.reopenDelay) else @open() ``` 這個文件只是定義了如何reopen的方法,默認reopen的時間延遲是500ms。 假如說,突然服務器掛了,這個時候掉線了,客戶端應該重新連接,但重新連接的次數總是有限的吧,不能一直進行下去。 這個就是`connection_monitor.coffee`所發揮的作用。 `ActionCable.Connection`也是會調用這個文件的內容的。 比如`constructor`方法中的`@monitor = new ActionCable.ConnectionMonitor this`,還有`open`方法中的`@monitor.start()`。 ##### 2.5 ActionCable.ConnectionMonitor 我們來看看`connection_monitor.coffee`的部分源碼: ``` class ActionCable.ConnectionMonitor @pollInterval: min: 3 max: 30 @staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings) constructor: (@connection) -> @reconnectAttempts = 0 start: -> unless @isRunning() @startedAt = now() delete @stoppedAt @startPolling() document.addEventListener("visibilitychange", @visibilityDidChange) ActionCable.log("ConnectionMonitor started. pollInterval = #{@getPollInterval()} ms") ``` 在閱讀源碼的時候,可以緊密結合日志來一起看的。 ##### 2.6 測試 現在我們來做一個實驗,把服務器停掉,看看瀏覽器的日志會輸出什么內容。 一關掉服務器,瀏覽器就馬上探測出服務器關閉了,并輸出了下面的信息: ``` [ActionCable] WebSocket onclose event 1462006781945 [ActionCable] ConnectionMonitor recorded disconnect 1462006781954 ``` 除此之外,接著輸出類似下面的信息: ``` [ActionCable] ConnectionMonitor detected stale connection. reconnectAttempts = 0, pollInterval = 3000 ms, time disconnected = 5.156 s, stale threshold = 6 s 1462007045080 [ActionCable] ConnectionMonitor detected stale connection. reconnectAttempts = 1, pollInterval = 3466 ms, time disconnected = 8.624 s, stale threshold = 6 s 1462007048548 [ActionCable] ConnectionMonitor detected stale connection. reconnectAttempts = 2, pollInterval = 5493 ms, time disconnected = 14.124 s, stale threshold = 6 s 1462007054048 ``` ##### 2.7 改寫 其實這些輸出信息都在`connection_monitor.coffee`文件中可以找到,主要就是`reconnectIfStale`這個方法: ``` reconnectIfStale: -> if @connectionIsStale() ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = #{@reconnectAttempts}, pollInterval = #{@getPollInterval()} ms, time disconnected = #{secondsSince(@disconnectedAt)} s, stale threshold = #{@constructor.staleThreshold} s") @reconnectAttempts++ if @disconnectedRecently() ActionCable.log("ConnectionMonitor skipping reopening recent disconnect") else ActionCable.log("ConnectionMonitor reopening") @connection.reopen() ``` 主要改寫這個方法,把日志輸出的部分效果改成在頁面上提示即可。 我是這樣改寫的: ``` App.cable.connection.monitor.reconnectIfStale = -> if App.cable.connection.monitor.connectionIsStale() $.notify("正在重新連接") App.cable.connection.monitor.reconnectAttempts++ if App.cable.connection.monitor.disconnectedRecently() else App.cable.connection.reopen( ``` 至于`$.notify`是使用了[notifyjs](https://notifyjs.com/)這個庫,你當然可以用你自己喜歡的庫,或者干脆自己修改樣式。 這樣就算完成了,不過為了圓滿,當連上服務器的時候,或掉線的時候也總有提示吧。 ``` # app/assets/javascripts/channels/room.coffee App.room = App.cable.subscriptions.create "RoomChannel", connected: -> $.notify("已連接到服務器", "success") disconnected: -> $.notify("已掉線", "warn") ``` ![](https://box.kancloud.cn/01214918bc41011025c449432caf687b_403x244.png) ![](https://box.kancloud.cn/98291f3c783f9f6c73555de36898001a_401x239.png) 本篇完結。 下一篇:[websocket之部署(十)](http://www.rails365.net/articles/websocket-zhi-bu-shu-shi)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看