0

我正在编写一个 Chrome 扩展程序来以与 Delicious 类似的方式存储链接。作为我的扩展的一部分,我想保存我正在存储的链接的关键字。为了获得这个关键字,我使用以下函数:

EXT.get_keywords = function (tab) {
var keywords = [];

    if(tab) {
        chrome.tabs.executeScript(tab.id, {file:"js/keywords.js"},
            (function(keywords) {
                return function (res) {
                    var kw_str = res && res[0];
                    if (kw_str) {
                        keywords.push.apply(keywords, kw_str.split(","));
                    }
                }
            })(keywords));
    }
    console.log(keywords);
    return keywords;
}    

“js/keywords.js”文件的内容如下:

var metas = document.getElementsByTagName('meta'),
    i = 0,
    result = "";

for (i = 0; i < metas.length; i++) {
    if (metas[i].getAttribute("name") === "keywords") {
        result = metas[i].getAttribute("content");
        break;
    }
}
result;

“js/keywords.js”脚本运行良好,回调函数从关键字标签中获取内容字符串(如果存在),但在执行回调后,关键字变量始终为[]. 任何想法?

PS:这很奇怪,因为如果我在该行执行带有断点的脚本,console.log(keywords)它可以工作,但如果断点不存在,它就不会:S。

4

1 回答 1

1

这是由于chrome.tabs.executeScript()的异步特性。您不能从get_keywords函数中返回关键字 - 实际上您可以返回一个空keywords数组,但在函数退出之前不会填充它。
(大多数chrome.* API 都是异步的,因此您必须调整整个扩展“样式”以符合这一点。)

那么,会发生什么?

这是执行顺序:

  1. keywords数组被初始化 ( var keywords = [];)。
  2. executeScript被称为在后台启动一些无趣的东西。
  3. (function(keywords) {...})(keywords)被调用,返回并注册一个回调(它绑定到仍然为空的keywords数组)。每次注入和执行结束后都会调用回调。
  4. executeScript返回(请注意,尚未执行任何回调 - 异步仍在后台执行操作,即注入和执行 JS)。
  5. console.log(keywords);记录(仍然是空的)keywords数组。
  6. 返回仍然为空的keywords数组 ( return keywords;)。
  7. 异步注入/执行结束并调用回调,填充keywords数组。

如果激活断点,则在到达第 5 步之前有时间完成注入/执行,因此keywords在返回之前填充数组。


演示这一点的示例扩展:

background.js中,keywords数组被记录了两次:一次是在它被返回之前,getKeywords()一次是在它被填充到回调中之后。如您所见,在返回一个空数组后执行登录回调。 getKeywords()

内容.js:

var metas = document.getElementsByTagName("meta");
var result = "";
for (var i = 0; i < metas.length; i++) {
    var meta = metas[i];
    if (meta.name && (meta.name.toLowerCase() === "keywords")) {
        result = meta.content;
        break;
    }
}
result;

背景.js:

function getKeywords(tab) {
    var keywords = [];

    chrome.tabs.executeScript(
            tab.id,
            { file: "/fg/content.js" },
            (function(keywords) {
                return function(resultArr) {
                    if (!chrome.runtime.lastError && resultArr[0]) {
                        keywords.push.apply(keywords, resultArr[0].split(","));
                    }
                    console.log("After: ", keywords);
                }
            })(keywords));
    console.log("Before: ", keywords);
}

chrome.browserAction.onClicked.addListener(getKeywords);

清单.json:

{
    "manifest_version": 2,
    "name":    "Test Extension",
    "version": "0.0",

    "background": {
        "persistent": false,
        "scripts": ["./bg/background.js"]
    },

    "browser_action": {
        "default_title": "Test Extension"
    },

    "permissions": ["activeTab"]
}
于 2013-11-11T12:28:13.633 回答