Javascript Firefox WebExtensions browser.tabs.query()返回的不可访问数组。有人能解释一下原因吗?

Javascript Firefox WebExtensions browser.tabs.query()返回的不可访问数组。有人能解释一下原因吗?,javascript,arrays,promise,firefox-addon,firefox-addon-webextensions,Javascript,Arrays,Promise,Firefox Addon,Firefox Addon Webextensions,有人能给我解释一下这里发生了什么事吗?我正在玩FirefoxWebExtensionsAPI,我遇到了一些相当奇怪的行为。下面是一些非常简单的代码来说明这个问题 我正在查询所有窗口中的所有固定选项卡,我希望全局数组var pinted=[]将用选项卡数据/对象填充。然而,至少可以说事情有点反常。数组似乎已填充,但无法使用标准数组表示法pinted[0]返回undefined。我对此感到十分困惑 这是怎么回事?这是关于范围还是权限的问题 现在代码 [manifest.json] { "mani

有人能给我解释一下这里发生了什么事吗?我正在玩FirefoxWebExtensionsAPI,我遇到了一些相当奇怪的行为。下面是一些非常简单的代码来说明这个问题

我正在查询所有窗口中的所有固定选项卡,我希望全局数组
var pinted=[]将用选项卡数据/对象填充。然而,至少可以说事情有点反常。数组似乎已填充,但无法使用标准数组表示法
pinted[0]
返回
undefined
。我对此感到十分困惑

这是怎么回事?这是关于范围还是权限的问题

现在代码

[manifest.json]

{
  "manifest_version": 2,
  "name": "test",
  "version": "1.0",
  "description": "test",
  "icons": {
    "48": "icons/page-48_white.png"
  },
  "permissions": [
    "tabs",
    "<all_urls>"
  ],
  "background": {
    "scripts": ["background.js"]
  },
  "devtools_page": "test.html",
  "browser_action": {
    "default_icon": { "48": "icons/page-48_white.png"},
    "default_title": "Test",
    "browser_style": true
  }
}
[test.js]

var pinned = [];

browser.tabs.query({pinned: true})
  .then(tabs => {
    for (let [key, value] of tabs.entries() ) {
      console.log("Object " + key, value);
      pinned.push(value);
    }
  });

console.debug("All Pinned Tabs", pinned);
console.debug("First Pinned Tab", pinned[0]);
现在看看Firefox开发者工具控制台的输出

  All Pinned Tabs
  []
    0: {…}
        active: false
        audible: false
        discarded: false
        favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
        height: 800
        hidden: false
        highlighted: false
        id: 149
        incognito: false
        index: 0
        isArticle: false
        isInReaderMode: false
        lastAccessed: 1522229700160
        mutedInfo: Object { muted: false }
        pinned: true
        sharingState: Object { camera: false, microphone: false }
        status: "complete"
        title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
        url: "http://www.crunchyroll.com/"
        width: 1440
        windowId: 3
        __proto__: Object { … }
  ​
    1: {…}
        active: false
        audible: false
        discarded: false
        favIconUrl: "https://www.pandora.com/favicon.ico"
        height: 800
        hidden: false
        highlighted: false
        id: 145
        incognito: false
        index: 0
        isArticle: false
        isInReaderMode: false
        lastAccessed: 1522447564848
        mutedInfo: Object { muted: false }
        pinned: true
        sharingState: Object { camera: false, microphone: false }
        status: "complete"
        title: "All Along The Watchtower Radio - Now Playing on Pandora"
        url: "https://www.pandora.com/station/play/3395036678172411653"
        width: 1440
        windowId: 67
        __proto__: Object { … }
  ​
    2: {…}
        active: false
        audible: false
        discarded: false
        height: 800
        hidden: false
        highlighted: false
        id: 171
        incognito: false
        index: 1
        isArticle: false
        isInReaderMode: false
        lastAccessed: 1522398347238
        mutedInfo: Object { muted: false }
        pinned: true
        sharingState: Object { camera: false, microphone: false }
        status: "complete"
        title: "Debugging with Firefox Developer Tools"
        url: "about:debugging"
        width: 1440
        windowId: 67
        __proto__: Object { … }
    length: 3
  ​  __proto__: Array []

  First Pinned Tab undefined

  Object 0
    {…}
      active: false
      audible: false
      discarded: false
      favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
      height: 800
      hidden: false
      highlighted: false
      id: 149
      incognito: false
      index: 0
      isArticle: false
      isInReaderMode: false
      lastAccessed: 1522229700160
      mutedInfo: Object { muted: false }
      pinned: true
      sharingState: Object { camera: false, microphone: false }
      status: "complete"
      title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
      url: "http://www.crunchyroll.com/"
      width: 1440
      windowId: 3
      __proto__: Object { … }

  Object 1
    {…}
      active: false
      audible: false
      discarded: false
      favIconUrl: "https://www.pandora.com/favicon.ico"
      height: 800
      hidden: false
      highlighted: false
      id: 145
      incognito: false
      index: 0
      isArticle: false
      isInReaderMode: false
      lastAccessed: 1522447564848
      mutedInfo: Object { muted: false }
      pinned: true
      sharingState: Object { camera: false, microphone: false }
      status: "complete"
      title: "All Along The Watchtower Radio - Now Playing on Pandora"
      url: "https://www.pandora.com/station/play/3395036678172411653"
      width: 1440
      windowId: 67
      __proto__: Object { … }

  Object 2
    {…}
      active: false
      audible: false
      discarded: false
      height: 800
      hidden: false
      highlighted: false
      id: 171
      incognito: false
      index: 1
      isArticle: false
      isInReaderMode: false
      lastAccessed: 1522398347238
      mutedInfo: Object { muted: false }
      pinned: true
      sharingState: Object { camera: false, microphone: false }
      status: "complete"
      title: "Debugging with Firefox Developer Tools"
      url: "about:debugging"
      width: 1440
      windowId: 67
      __proto__: Object { … }
这才是真正的怪事。如果我在firefox开发者工具控制台中键入
pinted[0]
,我会得到这个结果

pinned[0]
  {…}
    active: false
    audible: false
    discarded: false
    favIconUrl: "http://www.crunchyroll.com/favicon.ico?v=1"
    height: 800
    hidden: false
    highlighted: false
    id: 149
    incognito: false
    index: 0
    isArticle: false
    isInReaderMode: false
    lastAccessed: 1522229700160
    mutedInfo: Object { muted: false }
    pinned: true
    sharingState: Object { camera: false, microphone: false }
    status: "complete"
    title: "Crunchyroll - Watch Naruto Shippuden, Bleach, Anime Videos and Episodes Free Online"
    url: "http://www.crunchyroll.com/"
    width: 1440
    windowId: 3
    __proto__: Object { … }    
有什么好处?为什么我可以从控制台访问数组的元素,而不是代码


如您所见,已填充固定的数组,但我无法使用该数组访问其中的单个元素。有人知道为什么会这样吗

这实际上是异步代码和数组引用的问题。 让我们一步一步地试着看看这是怎么回事:

  • 您可以调用
    browser.tabs.query
    。它返回一个承诺,,但没有立即解决。因此,您暂时不进入
    然后
    部分,因此代码执行继续到下一部分
  • 这是
    console.debug(“所有固定选项卡”,固定)。您正在记录一个数组,因此给
    console.debug
    一个数组引用,这在这里非常重要。此引用不会随时间而更改:当您声明
    固定的
    数组以及脚本结束时,数组引用仍然相同
  • 然后转到
    console.debug(“第一个固定选项卡”,固定[0])。此时,承诺处理程序尚未执行,因此refore
    pinted
    仍然为空,
    pinted[0]
    实际上是
    未定义的。这就是
    未定义的
    被记录的原因
  • 承诺解决了:您通过
    然后
    处理程序,接收标签列表作为参数,并将标签推到您的
    固定的
    数组中
  • 请记住,您的第一个
    控制台.debug
    根据阵列引用记录阵列,该引用不会随时间变化。之后在控制台中查看阵列时,阵列已填充,您在控制台中访问的是处于最终状态的阵列。这就是为什么整个阵列的日志会打印阵列本身

    让我们确定一下 …通过一个小测试:在步骤2,我们不记录
    固定的
    数组本身,而是记录当前在
    固定的
    中的所有元素的
    id

    var pinned = [];
    
    browser.tabs.query({pinned: true})
      .then(tabs => {
        for (let [key, value] of tabs.entries() ) {
          console.log("Object " + key, value);
          pinned.push(value);
        }
      });
    
    // will log an empty array since pinned tab is still empty,
    // therefore, mapping tab ids will return an empty array
    console.warn("All Pinned Tabs", pinned.map((t) => t.id));
    // still undefined, nothing changed here
    console.warn("First Pinned Tab", pinned[0]);
    
    以下是您应该得到的:

    All Pinned Tabs : Array []
    First Pinned Tab undefined
    
    如何处理? 解决方案是在第一个承诺的末尾链接另一个承诺(这是可能的,因为每个
    处理程序返回一个新的承诺,因此您可以链接它们),如下所示:

    var pinned = [];
    
    browser.tabs.query({pinned: true})
      .then(tabs => {
        for (let [key, value] of tabs.entries() ) {
          console.log("Object " + key, value);
          pinned.push(value);
        }
      }).then( () => {
        // ✓ [1,4,3,2] or anything matching your tabs ids
        console.debug("All Pinned Tabs", pinned.map((t) => t.id));
        // ✓ First tab object: { ... } 
        console.debug("First Pinned Tab", pinned[0]);
      });
    
    现在您确实得到了预期的结果:

    All Pinned Tabs Array(4) [ 1, 4, 3, 2 ]
    First Pinned Tab Object { id: 1, index: 0, windowId: 3, highlighted: false … }
    

    请注意,不必为数组操作全局变量,您可以使第一个承诺返回一个数组,该数组将作为第二个承诺的参数。

    这实际上是异步代码和数组引用的问题。 让我们一步一步地试着看看这是怎么回事:

  • 您可以调用
    browser.tabs.query
    。它返回一个承诺,,但没有立即解决。因此,您暂时不进入
    然后
    部分,因此代码执行继续到下一部分
  • 这是
    console.debug(“所有固定选项卡”,固定)。您正在记录一个数组,因此给
    console.debug
    一个数组引用,这在这里非常重要。此引用不会随时间而更改:当您声明
    固定的
    数组以及脚本结束时,数组引用仍然相同
  • 然后转到
    console.debug(“第一个固定选项卡”,固定[0])。此时,承诺处理程序尚未执行,因此refore
    pinted
    仍然为空,
    pinted[0]
    实际上是
    未定义的。这就是
    未定义的
    被记录的原因
  • 承诺解决了:您通过
    然后
    处理程序,接收标签列表作为参数,并将标签推到您的
    固定的
    数组中
  • 请记住,您的第一个
    控制台.debug
    根据阵列引用记录阵列,该引用不会随时间变化。之后在控制台中查看阵列时,阵列已填充,您在控制台中访问的是处于最终状态的阵列。这就是为什么整个阵列的日志会打印阵列本身

    让我们确定一下 …通过一个小测试:在步骤2,我们不记录
    固定的
    数组本身,而是记录当前在
    固定的
    中的所有元素的
    id

    var pinned = [];
    
    browser.tabs.query({pinned: true})
      .then(tabs => {
        for (let [key, value] of tabs.entries() ) {
          console.log("Object " + key, value);
          pinned.push(value);
        }
      });
    
    // will log an empty array since pinned tab is still empty,
    // therefore, mapping tab ids will return an empty array
    console.warn("All Pinned Tabs", pinned.map((t) => t.id));
    // still undefined, nothing changed here
    console.warn("First Pinned Tab", pinned[0]);
    
    以下是您应该得到的:

    All Pinned Tabs : Array []
    First Pinned Tab undefined
    
    如何处理? 解决方案是在第一个承诺的末尾链接另一个承诺(这是可能的,因为每个
    处理程序返回一个新的承诺,因此您可以链接它们),如下所示:

    var pinned = [];
    
    browser.tabs.query({pinned: true})
      .then(tabs => {
        for (let [key, value] of tabs.entries() ) {
          console.log("Object " + key, value);
          pinned.push(value);
        }
      }).then( () => {
        // ✓ [1,4,3,2] or anything matching your tabs ids
        console.debug("All Pinned Tabs", pinned.map((t) => t.id));
        // ✓ First tab object: { ... } 
        console.debug("First Pinned Tab", pinned[0]);
      });
    
    现在您确实得到了预期的结果:

    All Pinned Tabs Array(4) [ 1, 4, 3, 2 ]
    First Pinned Tab Object { id: 1, index: 0, windowId: 3, highlighted: false … }
    
    请注意,您可以让第一个承诺返回一个数组,作为第二个承诺的参数,而不是为数组操作全局变量