Javascript 如何在chrome扩展中存储数据/结果,以及如何使用setTimeout以便只调用一次?

Javascript 如何在chrome扩展中存储数据/结果,以及如何使用setTimeout以便只调用一次?,javascript,google-chrome-extension,Javascript,Google Chrome Extension,我有一个chrome扩展,我想在特定时间运行一个webgl演示,然后获取该页面的每秒帧数,然后加载一个新的webgl演示,然后存储每秒帧数,并在4-5个webgl演示中继续此操作,如果未加载演示,则将结果存储为每秒通过和帧数或失败 我使用setTimeout在特定时间运行,然后清除它以停止第一个演示并加载第二个演示。但在我的扩展中,它一直在加载第二个,无法清除第二个演示的超时并转到第三个。 有谁能帮我找到正确的方法吗 background.js //var duration = 30; //va

我有一个chrome扩展,我想在特定时间运行一个webgl演示,然后获取该页面的每秒帧数,然后加载一个新的webgl演示,然后存储每秒帧数,并在4-5个webgl演示中继续此操作,如果未加载演示,则将结果存储为每秒通过和帧数或失败

我使用setTimeout在特定时间运行,然后清除它以停止第一个演示并加载第二个演示。但在我的扩展中,它一直在加载第二个,无法清除第二个演示的超时并转到第三个。 有谁能帮我找到正确的方法吗

background.js

//var duration = 30;
//var start_time = new Date();

var frames_per_demo = {};
var URL_1 = "http://david.alloza.eu/WebGL/morphing.html";
var URL_2 = "http://webglsamples.org/blob/blob.html";
var URL_3 = "http://webglsamples.org/dynamic-cubemap/dynamic-cubemap.html"
chrome.browserAction.onClicked.addListener(function(activeTab){
chrome.tabs.create({ url: URL_1 });
});

chrome.runtime.onMessage.addListener(function(msg, sender) {

if (msg.message === "TC_1") {
    window.clearTimeout(msg.timer_1);
    frames_per_demo.TC1_Result = msg.frames_1;
    window.alert("tc1 " + JSON.stringify(frames_per_demo));
    chrome.tabs.update({ url: URL_2 });

}
if (msg.message === "TC_2") {
    window.clearTimeout(msg.timer_2);
    frames_per_demo.TC2_Result = msg.frames_2;
    window.alert("tc2 " + JSON.stringify(frames_per_demo));
    chrome.tabs.update({ url: URL_3 });

}
if (msg.message === "TC_3") {
    window.clearTimeout(msg.timer_3);
    frames_per_demo.TC3_Result = msg.frames_3;
    window.alert("tc3 " + JSON.stringify(frames_per_demo)); 
}
});
content.js:-

console.log("content script started");

var tc1_timer = setTimeout(function(){
console.log("Starting morphing demo");
var frames_morphing_demo = document.getElementById("framerate").innerHTML;
chrome.runtime.sendMessage({"message": "TC_1", "frames_1":      frames_morphing_demo, "timer_1": tc1_timer});
}, 10000);


var tc2_timer = setTimeout(function(){
console.log("Starting blob");
var frames_blob_demo = document.getElementById("fps").innerHTML;
chrome.runtime.sendMessage({"message": "TC_2", "frames_2": frames_blob_demo, "timer_2": tc2_timer});
}, 20000);

var tc3_timer = setTimeout(function(){
console.log("Starting cubemap");
var frames_cubemap_demo = document.getElementById("fps").innerHTML;
chrome.runtime.sendMessage({"message": "TC_3", "frames_3": frames_cubemap_demo, "timer_3": tc3_timer});
}, 30000);
manifest.json

{
"name": "store FPS data",
"version": "1",
"browser_action":
{
    "default_icon": "Test.png"
},
"background":{
 "scripts": ["background.js"],
 "persistent": true
 },
"content_scripts": [
{
    "matches": ["http://*/*", "https://*/*"],
    "js": ["content.js"],
    "run_at": "document_end",
    "all_frames": false
}
],
"permissions": ["tabs", "storage"],
"manifest_version": 2
}

整个想法是一个接一个地运行所有演示,如果任何演示加载不正确,则显示/存储fail else Pass和FPS数据。 有人能帮上忙吗?

每当你导航时(例如,使用
chrome.tabs.update({url:url\u 2});
,但每次导航都会发生这种情况)附加到页面的JS上下文被完全删除。您的内容脚本无法保存

因此,您的内容脚本只是重新启动(因为它是在导航之后重新注入的)。而且,计时器不会跨页面共享,所以您不能从后台取消计时器

此外,由于它被设置为加载到每个页面中,因此使浏览无法使用:

  • 如果任何页面碰巧有
    #framerate
    #fps
    元素,它将向您的扩展发送信号,选项卡将被劫持
  • 如果页面没有这样的元素,那么脚本在尝试访问
    null.innerHTML
一个好的策略是将状态保持在后台页面本身,并且以编程方式注入脚本,而不是到处注入脚本

因此:

1) 从清单中删除内容脚本部分,并将测试的URL添加到
“权限”
(注入所需)。顺便说一下,您不需要
“tabs”
权限

2) 制作一个在两个页面上都能工作的通用脚本:

setTimeout(function(){
  var fps_element = document.getElementById("framerate") ||
                    document.getElementById("fps");
  if(fps_element) {
    var fps = fps_element.innerHTML;
    chrome.runtime.sendMessage(
      {"message": "FPS", "frames": fps});
  } else {
    // No such element found; fail somehow
  }
}, 10000);
3) 跟踪状态并根据需要在后台注入脚本:

var test = 0;

chrome.browserAction.onClicked.addListener(function(activeTab){
  if(test == 0) { // Only react if test is not running yet
    chrome.tabs.create({ url: URL_1 }, function(tab) {
      chrome.tabs.executeScript(tab.id, {file: "content.js"});
    });
    test = 1;
  }
});

chrome.runtime.onMessage.addListener(function(msg, sender) {
  if (msg.message === "FPS") {
    switch(test) {
      case 1:
        frames_per_demo.TC1_Result = msg.frames;
        // You really shouldn't use `alert`, since it blocks execution;
        // Try chrome.notifications? Or use console for debugging.
        alert("tc1 " + JSON.stringify(frames_per_demo));
        test = 2;
        chrome.tabs.update(sender.tab.id, { url: URL_2 }, function(tab) {
          chrome.tabs.executeScript(tab.id, {file: "content.js"});
        });
        break;
      case 2:
        frames_per_demo.TC2_Result = msg.frames;
        alert("tc2 " + JSON.stringify(frames_per_demo));
        test = 3;
        chrome.tabs.update(sender.tab.id, { url: URL_3 }, function(tab) {
          chrome.tabs.executeScript(tab.id, {file: "content.js"});
        });
        break;
      case 3:
        frames_per_demo.TC3_Result = msg.frames;
        alert("tc3 " + JSON.stringify(frames_per_demo));
        test = 0;
        chrome.tabs.remove(sender.tab.id);
        break;
      default:
        // Unexpected, fail somehow
    }
  }
});
我留下了代码和你使用的结构<如果切换到使用URL数组和测试结果,则可以抛出代码>开关,以获得更好的代码


失败留给读者作为练习。

Hi Xan,非常感谢您简洁的实现和想法。但是,如果我从manifest.json中删除content_脚本部分,chrome.tabs.executeScript(tab.id,{file:“content.js”})将无法工作。但正如您正确指出的,如果我保留content_脚本部分,它确实会执行脚本,但会一次又一次地保留第一个实例。你知道我如何摆脱它吗?你忘了添加主机权限(步骤1)。没有它们,就不允许注入。我在manifest.json中添加了URL的权限,如下所示。哦,该死,你说得对。这是我的错。第一次我忘了注入脚本。请参阅
chrome.tabs.create
{“名称”:“chrome图形测试”,“版本”:“1”,“浏览器操作”:{“默认图标”:“Test.png”},“背景”:{“脚本”:[“background.js”],“persistent”:true},“权限”:[“选项卡”,“存储”、“”、“”、“”、“”、“”、”,“清单版本”:2}
case 1:
    // Try chrome.notifications? Or use console for debugging.
    frames_per_demo.TC1_Result = msg.frames;
    //alert("tc1 " + JSON.stringify(frames_per_demo));
    test = 2;
    chrome.tabs.update(sender.tab.id, { url: URL_2 }, function(tab) {
      **setTimeout(function(){
      chrome.tabs.executeScript(tab.id, {file: "content.js"});},10000);**
    });
    break;