Mozilla WebExtension API存储-在有断点和无断点的情况下进行调试都会导致不同的输出

Cpt*_*ook 2 javascript firefox-addon firefox-addon-webextensions


大家好,
我正在尝试为Mozilla-Firefox浏览器实现一个附件。以下脚本显示了一个我已经成功集成的backgorund脚本。它使用Mozilla WebExtension API存储。它被执行了,但是浏览器控制台上的日志使我惊讶。我交替登录没有任何东西,并且:

bla
bla
bla
Run Code Online (Sandbox Code Playgroud)

当且仅当在调试模式下在代码的重要行(尤其是最后5行)上设置断点时,我始终可以获得预期的结果:

bla
Run Code Online (Sandbox Code Playgroud)

输出如何取决于设置的断点。我不知道发生了什么,也无法在互联网上找到任何类似的问题。有人可以向我解释正在发生的事情以及我可以做些什么来防止错误的输出吗?

storeManager.js:

var localStore = chrome.storage.local;  
var StoreManager = function(){};

StoreManager.prototype.addItem = function(type, item){
    var thisRef = this;

    localStore.get(type, 
        function(obj){
            if(chrome.runtime.lasterror){
                console.log(chrome.runtime.lastError);
            }else{
                var oldArr = obj[type];

                if(oldArr === undefined)
                    oldArr = [];

                if(oldArr.indexOf(item) !== -1)
                    return;

                oldArr.push(item);
                thisRef.setItem(type, oldArr);
            }
        }
    );
}

StoreManager.prototype.removeItem = function(type, item){
    var thisRef = this;

    localStore.get(type, 
        function(obj){
            if(chrome.runtime.lasterror){
                console.log(chrome.runtime.lastError);
            }else{
                var oldArr = obj[type];

                if(oldArr === undefined)
                    return;

                var index = oldArr.indexOf(item);
                if(index === -1)
                    return;

                oldArr.splice(index, 1);
                thisRef.setItem(type, oldArr);
            }   
        }
    );
}

StoreManager.prototype.setItem = function(type, item){
    localStore.set({ [type] : item }, 
        function(){
            if(chrome.runtime.lasterror){
                console.log(chrome.runtime.lastError);
            }
        }
    );
}

StoreManager.prototype.visitItems = function(type, visit){
    localStore.get(type, 
        function(obj){
            if(chrome.runtime.lasterror){
                console.log(chrome.runtime.lastError);
            }else{
                var oldArr = obj[type];

                if(oldArr !== undefined){
                    for(var i=0; i<oldArr.length; i++){
                        visit(oldArr[i]);
                    }
                }
            }
        }
    );
}

function justLog(str){
    console.log(str);
}

var sm = new StoreManager();
sm.visitItems("lol", justLog);
sm.addItem("lol", "bla");
sm.visitItems("lol", justLog);
sm.removeItem("lol", "bla");
sm.visitItems("lol", justLog);
Run Code Online (Sandbox Code Playgroud)


manifest.json:

{
    "manifest_version": 2,
    "name": "Addon",
    "version": "0.0",

    "description": "no desc",

    "background": {
        "scripts": [
            "storeManager.js"
        ]
    },

    "permissions": [
        "storage"
    ]
}
Run Code Online (Sandbox Code Playgroud)

小智 5

storage.local.set()是异步的。在调用get()回调之前,不能保证对调用可见的数据(或者,如果您使用browser.storage.localset()将返回一个Promise,并且保证在Promise解析后将数据写入)。

您的代码天生就充满了竞争条件。到通话addItem()removeItem()争分夺秒的调用visitItems(),通过设置断点,你让一个路径或其他“赢”的比赛。

如果您希望获得确定性的结果,我建议您使用Promise的Promise变体storage.local并将您的代码编写为一系列链接的处理程序。