ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

多页签websocket 共享

2022-04-24 22:00:55  阅读:230  来源: 互联网

标签:function websocket return win storage 多页 共享 data event


网上搜索类似的问题方法讲的都很不错,以下是一个简答说明

问题来源

主要是看到atmosphere 的js client 看到支持多页签websocket 共享,比较好奇,顺带看了下实现机制,发现居然是基于了
localStorage的storage event 实现上还是比较巧妙,功能还是很强大的

参考处理

 
function _execute() {
                // Shared across multiple tabs/windows.
                if (_request.shared) {
                       // windows 以及tabs 共享
                    _localStorageService = _local(_request);
                    if (_localStorageService != null) {
                        if (_canLog('debug')) {
                            atmosphere.util.debug("Storage service available. All communication will be local");
                        }
 
                        if (_localStorageService.open(_request)) {
                            // Local connection.
                            return;
                        }
                    }
 
                    if (_canLog('debug')) {
                        atmosphere.util.debug("No Storage service available.");
                    }
                    // Wasn't local or an error occurred
                    _localStorageService = null;
                }
   

_local 的处理

function _local(request) {
                var trace, connector, orphan, name = "atmosphere-" + request.url, connectors = {
                    // 基于localstorage 的处理
                    storage: function () {
                        function onstorage(event) {
                            if (event.key === name && event.newValue) {
                                // 处理消息
                                listener(event.newValue);
                            }
                        }
 
                        if (!atmosphere.util.storage) {
                            return;
                        }
 
                        var storage = window.localStorage,
                            get = function (key) {
                                var item = storage.getItem(name + "-" + key);
                                return item === null ? [] : JSON.parse(item);
                            },
                            set = function (key, value) {
                                storage.setItem(name + "-" + key, JSON.stringify(value));
                            };
 
                        return {
                            init: function () {
                                set("children", get("children").concat([guid]));
                                atmosphere.util.on(window, "storage", onstorage);
                                return get("opened");
                            },
                            signal: function (type, data) {
                                storage.setItem(name, JSON.stringify({
                                    target: "p",
                                    type: type,
                                    data: data
                                }));
                            },
                            close: function () {
                                var children = get("children");
 
                                atmosphere.util.off(window, "storage", onstorage);
                                if (children) {
                                    if (removeFromArray(children, request.id)) {
                                        set("children", children);
                                    }
                                }
                            }
                        };
                    },
                    windowref: function () {
                        var win = window.open("", name.replace(/\W/g, ""));
 
                        if (!win || win.closed || !win.callbacks) {
                            return;
                        }
 
                        return {
                            init: function () {
                                win.callbacks.push(listener);
                                win.children.push(guid);
                                return win.opened;
                            },
                            signal: function (type, data) {
                                if (!win.closed && win.fire) {
                                    win.fire(JSON.stringify({
                                        target: "p",
                                        type: type,
                                        data: data
                                    }));
                                }
                            },
                            close: function () {
                                // Removes traces only if the parent is alive
                                if (!orphan) {
                                    removeFromArray(win.callbacks, listener);
                                    removeFromArray(win.children, guid);
                                }
                            }
 
                        };
                    }
                };
 
                function removeFromArray(array, val) {
                    var i, length = array.length;
 
                    for (i = 0; i < length; i++) {
                        if (array[i] === val) {
                            array.splice(i, 1);
                        }
                    }
 
                    return length !== array.length;
                }
 
                // Receives open, close and message command from the parent
                function listener(string) {
                    var command = JSON.parse(string), data = command.data;
                    // 基于协议处理消息
                    if (command.target === "c") {
                        switch (command.type) {
                            case "open":
                                _open("opening", 'local', _request);
                                break;
                            case "close":
                                if (!orphan) {
                                    orphan = true;
                                    if (data.reason === "aborted") {
                                        _close();
                                    } else {
                                        // Gives the heir some time to reconnect
                                        if (data.heir === guid) {
                                            _execute();
                                        } else {
                                            setTimeout(function () {
                                                _execute();
                                            }, 100);
                                        }
                                    }
                                }
                                break;
                            // 消息处理
                            case "message":
                               // 消息处理
                                _prepareCallback(data, "messageReceived", 200, request.transport);
                                break;
                            // 本地消息处理
                            case "localMessage":
                                _localMessage(data);
                                break;
                        }
                    }
                }
 
                function findTrace() {
                    var matcher = new RegExp("(?:^|; )(" + encodeURIComponent(name) + ")=([^;]*)").exec(document.cookie);
                    if (matcher) {
                        return JSON.parse(decodeURIComponent(matcher[2]));
                    }
                }
 
                // Finds and validates the parent socket's trace from the cookie
                trace = findTrace();
                if (!trace || atmosphere.util.now() - trace.ts > 1000) {
                    return;
                }
 
                // Chooses a connector
                connector = connectors.storage() || connectors.windowref();
                if (!connector) {
                    return;
                }
 
                return {
                    open: function () {
                        var parentOpened;
 
                        // Checks the shared one is alive
                        _traceTimer = setInterval(function () {
                            var oldTrace = trace;
                            trace = findTrace();
                            if (!trace || oldTrace.ts === trace.ts) {
                                // Simulates a close signal
                                listener(JSON.stringify({
                                    target: "c",
                                    type: "close",
                                    data: {
                                        reason: "error",
                                        heir: oldTrace.heir
                                    }
                                }));
                            }
                        }, 1000);
 
                        parentOpened = connector.init();
                        if (parentOpened) {
                            // Firing the open event without delay robs the user of the opportunity to bind connecting event handlers
                            setTimeout(function () {
                                _open("opening", 'local', request);
                            }, 50);
                        }
                        return parentOpened;
                    },
                    send: function (event) {
                        connector.signal("send", event);
                    },
                    localSend: function (event) {
                        connector.signal("localSend", JSON.stringify({
                            id: guid,
                            event: event
                        }));
                    },
                    close: function () {
                        // Do not signal the parent if this method is executed by the unload event handler
                        if (!_abortingConnection) {
                            clearInterval(_traceTimer);
                            connector.signal("close");
                            connector.close();
                        }
                    }
                };
            }

说明:以上代码处理还是比较复杂的,核心上还是利用了localStorage的storage event,因为消息框架的复杂性,以上代码做了不少消息协议的处理
而且同时也包含了处理多windows的共享,很值得仔细研究下

参考资料

https://juejin.cn/post/6844904163533389837
https://juejin.cn/post/6844903811232825357
http://www.w3.org/TR/webstorage/#event-storage
https://github.com/Atmosphere/atmosphere-javascript
https://developer.mozilla.org/en-US/docs/web/api/window/open

标签:function,websocket,return,win,storage,多页,共享,data,event
来源: https://www.cnblogs.com/rongfengliang/p/16187850.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有