2


大家好,
我正在尝试为 Mozilla-Firefox 浏览器实现一个附加组件。以下脚本显示了我已经成功集成的一个背景脚本。它使用 Mozilla WebExtension API 存储。它被执行,但浏览器控制台上的日志让我吃惊。我没有得到交替记录,并且:

bla
bla
bla

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

bla

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

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);


清单.json:

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

    "description": "no desc",

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

    "permissions": [
        "storage"
    ]
}
4

1 回答 1

5

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

您的代码本质上充满了竞争条件。调用addItem()removeItem()正在与调用竞争visitItems(),通过设置断点,您可以让一条路径或另一条路径“赢得”比赛。

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

于 2016-08-08T03:56:46.167 回答