Synchronization 通过附加选项卡禁用PockDB实时同步

Synchronization 通过附加选项卡禁用PockDB实时同步,synchronization,pouchdb,Synchronization,Pouchdb,当同一个数据库在同一浏览器的多个选项卡中实例化时,with POCKDB禁止同步。在我的测试中(6.4.1,Chrome上有同步网关),这个问题的深度比尝试实例化一个新的同步进程要严重得多 据我所知,每当一个新选项卡尝试实例化同一同步进程的新实例时,DBSYNC也会禁用在原始选项卡中发生的同步进程 我不确定它是如何做到这一点的,因为另一个进程是在一个单独的窗口中运行的,但我注意到原来的选项卡不再推拉更改。此外,原始选项卡无法知道它已被禁用(因为它不会发出错误、更改或状态来指示这种情况)。而且,在

当同一个数据库在同一浏览器的多个选项卡中实例化时,with POCKDB禁止同步。在我的测试中(6.4.1,Chrome上有同步网关),这个问题的深度比尝试实例化一个新的同步进程要严重得多

据我所知,每当一个新选项卡尝试实例化同一同步进程的新实例时,DBSYNC也会禁用在原始选项卡中发生的同步进程

我不确定它是如何做到这一点的,因为另一个进程是在一个单独的窗口中运行的,但我注意到原来的选项卡不再推拉更改。此外,原始选项卡无法知道它已被禁用(因为它不会发出错误、更改或状态来指示这种情况)。而且,在PockDB中似乎没有办法检查另一个窗口是否在尝试启动同步进程(并遇到错误)之前已经有了同步进程

因此,任何依赖
{live:true,retry:true}
自动传播客户端更改的web应用程序,如果/当用户打开第二个选项卡时,都可能丢失数据。数据将仅与服务器再次同步一次:

  • 所有打开的选项卡都将关闭
  • 将打开一个新选项卡
  • 签出/销毁事件不会在1和2之前发生
  • 这也会立即禁用服务器希望发送给客户端的任何更改

    有人找到解决办法了吗

    通过检查同步是否已在运行,或者在禁用同步时重新启动同步?还是其他方法?否则,在用户一次可能打开多个选项卡的生产环境中,似乎无法使用实时同步。避免此问题的唯一方法似乎是按需执行复制


    已解决:问题似乎来自浏览器的原始请求限制,而不是数据库。在同一地址上同时运行太多同步进程会导致浏览器以不报告错误的方式禁用这些进程。感谢Dale Harvey的帮助。

    我发现解决同步问题的一个方法是使用页面可见性API事件侦听器来打开/关闭同步。以下代码适用于关于停止和启动同步的另一个SO答案:

    function VisibilityListener(callback=null) {
    
        var hidden = "hidden";
    
    // Standards:
        if (hidden in document){
            document.addEventListener("visibilitychange", onchange);
        } else if ((hidden = "mozHidden") in document){
            document.addEventListener("mozvisibilitychange", onchange);
        } else if ((hidden = "webkitHidden") in document){
            document.addEventListener("webkitvisibilitychange", onchange);
        } else if ((hidden = "msHidden") in document){
            document.addEventListener("msvisibilitychange", onchange);
        }
    // IE 9 and lower:
        else if ("onfocusin" in document){
            document.onfocusin = document.onfocusout = onchange;
        }
    // All others:
        else {
            window.onpageshow = window.onpagehide = window.onfocus = window.onblur = onchange;
        }
    
    // define function for change of status
        function onchange (evt) {
            var v = "visible"
            var h = "hidden"
            var evtMap = {
                focus:v, 
                focusin:v, 
                pageshow:v, 
                blur:h, 
                focusout:h, 
                pagehide:h
            }
    
            evt = evt || window.event;
            if (evt.type in evtMap){
                document.body.className = evtMap[evt.type];
            } else {
                document.body.className = this[hidden] ? "hidden" : "visible";
            }
            if (callback){
                callback(document.body.className)
            }
        }
    
    // set the initial state (but only if browser supports the Page Visibility API)
        if ( document[hidden] !== undefined ){
            onchange({type: document[hidden] ? "blur" : "focus"});
        }
    
    }
    
    (function(){
    
        VisibilityListener(function(state){
    
            var sync_process = 'mydb_sync'
            var local_key = 'mydb'
            var remote_url = 'http://localhost:4984/mydb'
            var sync_options = { live: true, retry: true }
    
        // if window changes to visible state, start or restart sync
            if (state == 'visible'){
                window[sync_process] = PouchDB.sync(local_key, remote_url, sync_options)
    
        // if window changes to hidden state, stop sync
            } else if (state == 'hidden'){
                if (sync_process in window){
                    window[sync_process].cancel()
                }
            }
        })
    
    })();
    

    看一看。它以多种方式扩展了PockDB,可能做的比您需要的多得多,但它解决了多选项卡同步问题。

    我觉得这并不是万无一失的——在某些环境中,可能同时有多个活动窗口。另外,窗口活动似乎并不是您所关心的,但同步独占性才是重要的,因此将锁定条件与之绑定似乎更可取。为什么不使用本地存储备份锁?只有在可以获得锁的情况下才启动同步过程,同步完成后,释放锁。好主意。。。我尝试过的想法之一是在本地存储字段中声明每个同步进程,以表明它已经在运行。但是,我发现刷新窗口会挫败我的设计。。。因为“锁”将保留在本地存储中,但同步过程本身消失了。我不想检查是否有卸载事件来解锁进程:不幸的是。。。卸载也不是万无一失的,有许多情况下它不会触发,在不应该触发的情况下将localstorage锁定。我认为这个问题的真正解决方案是通过PockDB向上游发送事件(或者执行按需复制)。