node.js / socket.io:重新连接刷新表?

我有node.js和socket.io在DataTables表上执行实时更新。 当一行被编辑时,其他客户端看到行的更新而不刷新。

这一切都运行良好,但是我不知道如何在断开连接后将节点/套接字重新连接到服务器时自动刷新表。

目前,这是发生了什么事情:

  1. 转到包含表的页面
  2. 让设备睡眠/从服务器断开连接
  3. 打开设备电源并查看包含表格的页面
  4. socket.io重新连接到服务器,但表不刷新以获取最新的更改。

我怎样才能得到socket.io重新连接到服务器刷新表? 理想情况下,这个过程看起来像这样:

  1. 打开设备电源
  2. socket.io重新连接到服务器,触发CSS“Loading …”叠加,以防止用户对表进行更改
  3. socket.io刷新表以显示最新的内容
  4. CSS“Loading …”叠加closures

服务器端脚本:

console.log('Starting the server'); var app = require('express')(); var express = require('express'); var fs = require("fs"); var server = require('https').createServer(SSL, app); var io = require('socket.io')(server); server.listen(100); io.on('connection', function (socket) { /*socket.emit('news', { hello: 'world' }); /socket.on('my other event', function (data) { console.log(data); });*/ }); io.set('authorization', function(handshakeData, accept) { console.log('io.authorization called'); accept(null, true); } ); var lockedRowIDs = []; io.sockets.on('connection', function(socket) { console.log('io.connection called'); socket.on('lock', function(rowID) { console.log('Lock event for rowID: '+rowID); lock(socket, rowID); lockedRowIDs.push(rowID); } ); socket.on('clientJoin', function(username) { console.log('clientJoin event received'); socket.join('clients'); if (typeof lockedRowIDs !== 'undefined' && lockedRowIDs.length > 0) { socket.emit('lockedRows', lockedRowIDs); } } ); socket.on('unlock', function(rowID) { console.log('Unlock event for rowID: '+rowID); unlock(socket, rowID); removeItemFromArray(lockedRowIDs, rowID); } ); socket.on('updateData', function(json, action, id) { if (action == "edit" || action == "create") { console.log('updateData event for rowID: '+json.row['DT_RowId']); } updateData(socket, json, action, id); } ); } ); function lock(socket, rowID) { socket.broadcast.to('clients').emit('lock', rowID); setTimeout(function() { io.sockets.in('clients').emit('timeout', rowID); removeItemFromArray(lockedRowIDs, rowID); }, 180000); } function unlock(socket, rowID) { socket.broadcast.to('clients').emit('unlock', rowID); } function removeItemFromArray(array, item) { console.log('removeItemFromArray called with item: '+item); for(var i = array.length - 1; i >= 0; i--) { if(array[i] === item) { array.splice(i, 1); } } } function updateData(socket, json, action, id) { if (action == "edit" || action == "create") { console.log('updateData called with rowID:'+json.row['DT_RowId']); } socket.broadcast.to('clients').emit('updateData', json, action, id); } 

客户端脚本:

 var socket = io('https://www.***.com:100'); socket.on('connect', function() { console.log('Connected'); socket.emit('clientJoin'); } ); socket.on('lock', function(rowID) { console.log('Lock event received for rowID: '+rowID); row = $("tr[id='"+rowID+"']"); row.addClass('locked'); /* Pagenation fix Start */ var table = $('#example').DataTable(); table.row('#'+rowID).nodes().to$().addClass('locked'); /* Pagenation fix End */ } ); socket.on('unlock', function(rowID) { console.log('Unlock event received for rowID: '+rowID); row = $("tr[id='"+rowID+"']"); row.removeClass('locked'); /* Pagenation fix Start */ var table = $('#example').DataTable(); table.row('#'+rowID).nodes().to$().removeClass('locked'); /* Pagenation fix End */ } ); socket.on('timeout', function(rowID) { console.log('Time out event received for rowID: '+rowID); row = $("tr[id='"+rowID+"']"); row.removeClass('locked'); /* Pagenation fix Start */ var table = $('#example').DataTable(); table.row('#'+rowID).nodes().to$().removeClass('locked'); /* Pagenation fix End */ /* Check if the editor corresponds to the timed out rowID - start */ var modifier = editor.modifier(); if (modifier) { var data = table.row(modifier).data(); console.log('rowID is '+data.DT_RowId); if (data.DT_RowId == rowID) { console.log('Timed out rowID: '+rowID+' matches Editor rowID: '+data.DT_RowId+'. Closing Editor now.'); editor.close(); } else { console.log('Timed out rowID: '+rowID+' does not match Editor rowID: '+data.DT_RowId+'. Keeping Editor open.'); } } /* Check if the editor corresponds to the timed out rowID - end */ } ); socket.on('lockedRows', function (rowIDs) { console.log('Iterate through the list of rows and mark it as locked'); table = $('#example').DataTable(); rowCount = rowIDs.length; console.log('Row count: '+rowCount); for (var i=0; i<rowCount; i++) { console.log(rowIDs[i]); row = $("tr[id='"+rowIDs[i]+"']"); row.addClass('locked'); table.row('#'+rowIDs[i]).nodes().to$().addClass('locked'); } } ); socket.on('updateData', function(json, action, id) { if (action == "create" || action == "edit") { var DT_RowId = json.row['DT_RowId']; console.log('updateData socket event for rowID: '+DT_RowId+' and action: '+action); } var table = $('table#example').DataTable(); if (action == "edit") { var editedRow = table.row('#'+DT_RowId).nodes().to$(); table.row(editedRow).data(json.row).draw(); console.log('Row updated'); } if (action == "create") { console.log('Row created'); table.row.add(json.row).draw(); } if (action == "remove") { var removedRow = table.row('#'+id).nodes().to$(); table.row(removedRow).remove().draw(); console.log('Row removed with id '+id); } } ); /* Ajax request has been completed, data retrieved from the server */ editor.on('postSubmit', function(e,json, data, action) { console.log('Post submit'); console.log(data); console.log('With JSON:'); console.log(json); console.log('With action:'); console.log(action); if (action == "create" || action== "edit") { if (json.row){ console.log('rowID from JSON: '+json.row['DT_RowId']); socket.emit('updateData', json, action); } } if (action == "remove") { console.log('rowID from JSON: '+data.id[0]); socket.emit('updateData', null, action, data.id[0]); } } ); editor.on('close', function(e) { console.log('Close event'); console.log(e); var modifier = editor.modifier(); console.log(modifier) if (modifier !== null) { console.log('Inside modifier') table = $('#example').DataTable(); if (table.row(modifier).node()) { rowID = table.row(modifier).node().id; console.log('rowID='+rowID); row = $("tr[id='"+rowID+"']"); row.removeClass('locked'); table.row('#'+rowID).nodes().to$().removeClass('locked'); socket.emit('unlock', rowID); } } } ); 

我想你知道,当你连接时,你保持数据是最新的,但如果你有一个短暂的断开连接,然后重新连接,你可能已经错过了一些数据更新。

有许多可能的策略来处理这个问题。

  1. 蛮力。 重新连接后,获取所有数据的全新副本,就好像设备刚打开一样。 效率较低,但易于实施。

  2. 交易ID或交易时间。 每次服务器发送更新时,它都会发送一个事务ID或事务服务器时间与更新。 然后,客户端会跟踪它收到的最后一个交易ID或交易时间。 当它进行重新连接时,它会发送一个包含最后一个事务ID或事务时间的初始消息,询问自上次事务以来发生的任何更新。 然后,服务器可以查看其数据库以查看是否有新的事务,如果是,则将它们发送给该客户端。 这需要跟踪数据库中的事务。 通常服务器可能会返回一个“不支持的事务ID”types的响应,然后强制客户端重新从头开始进行暴力更新。 如果数据库重build或服务器崩溃导致旧的事务值丢失,这是一个反向停止。

  3. 真正的同步。 客户端重新连接,然后与服务器进行真正的同步,客户端基本上说:“这是我的,你有什么新东西”。 为了提高效率,许多同步系统通过实现选项2中描述的事务ID来解决这个问题,但是确实有许多其他的同步方法。 如果客户端在断开连接时也可能正在更改数据,则真正同步更有用。

作为实现选项2的简化方式,如果您的数据库尚不支持日志logging事务的概念,则某些服务器将在内存中实现事务日志,在该日志中logging最近N小时的事务。 只要服务器保持运行并且断开连接的时间不超过N小时,则可以从内存事务日志(这是有效的)中满足对新数据的请求。 如果服务器重新启动或客户端已经超过N个小时,那么客户端只需要进行暴力破解更新,就像客户端关机后重新开机一样(丢失全部事先知道的数据)。

当然,如果数据库有多个用户,那么事务日志必须由数据库本身来实现,以确保它包含所有可能的事务。