首页 > 解决方案 > 对象中的数组在传递或 JSON.stringified 时为空

问题描述

我正在创建一个 Chrome 扩展程序,我在其中将一个对象(connectionStatus)从后台脚本发送到内容脚本。该对象包含一个数组 (supportedServiceContracts),当我在 content.js 中记录该对象时,该数组为空,即使我在发送它之前在 background.js 中记录它时可以看到它有数据。

这是为什么?

更新:

我还应该提到,如果我在对象上应用JSON.stringify(),对象的数组部分会变空。见截图。

在此处输入图像描述

背景.js

chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, { file: "axios.min.js" });
chrome.tabs.executeScript(tab.id, { file: "content.js" });

var connectionStatus = {};

chrome.tabs.query({
    active: true,
    currentWindow: true
    },
    function(tabs) {
        var tab = tabs[0];
        var url = tab.url;
        var urlString = new URL(url);
        var childHSAId = urlString.searchParams.get("childhsaid");

        if (childHSAId) {
            var healthcareFacilityHSAId = urlString.searchParams.get("hsaid");
            connectionStatus.healthcareFacilityHSAId = healthcareFacilityHSAId;
            connectionStatus.childHSAId = childHSAId;
            getConnectionStatusData(childHSAId);                
        } else {
            var healthcareFacilityHSAId = urlString.searchParams.get("hsaId");
            connectionStatus.healthcareFacilityHSAId = healthcareFacilityHSAId;
            getConnectionStatusData(healthcareFacilityHSAId);
        }

});

async function getConnectionStatusData(logicalAddress) {

    let serviceDomains = await axios.get('http://api.ntjp.se/coop/api/v1/serviceDomains.json', {
                                params: {
                                    namespace: "crm:scheduling"
                                }
                            });

    serviceDomainId = serviceDomains.data[0].id;

    let connectionPoints = await axios.get('http://api.ntjp.se/coop/api/v1/connectionPoints.json', {
                                params: {
                                    platform: "NTJP",
                                    environment: "PROD"
                                }
                            });

    connectionPointId = connectionPoints.data[0].id;

    var d = new Date(connectionPoints.data[0].snapshotTime);
    var options = { hour: '2-digit', minute:'2-digit' };

    snapshotTime = d.toLocaleDateString('se-SE', options)

    connectionStatus.snapshotTime = snapshotTime;

    let logicalAddresss = await axios.get('http://api.ntjp.se/coop/api/v1/logicalAddresss.json', {
                                params: {
                                    logicalAdress: logicalAddress,
                                    serviceConsumerHSAId: "SE2321000016-92V4",
                                    connectionPointId: connectionPointId
                                }
                            });

    if (logicalAddresss.data === undefined || logicalAddresss.data.length == 0) {

        connectionStatus.errorMessage = "HSA-id " + logicalAddress + " är inte registrerat i Ineras API för Etablerad samverkan i vården. API:t uppdaterades med data från Nationella tjänsteplattformens tjänstekatalog vid " + snapshotTime + ".";

        sendMessage();

        return;

    } else {

        logicalAddressId = logicalAddresss.data[0].id;

    }

    let serviceConsumers = await axios.get('http://api.ntjp.se/coop/api/v1/serviceConsumers.json', {
                                params: {
                                    connectionPointId: connectionPointId,
                                    logicalAddressId: logicalAddressId
                                }
                            });

    consumer = serviceConsumers.data.filter(obj => {
          return obj.hsaId === "SE2321000016-92V4"
        });

    serviceConsumerId = consumer[0].id;

    let cooperations = await axios.get('http://api.ntjp.se/coop/api/v1/cooperations.json', {
                                params: {
                                    connectionPointId: connectionPointId,
                                    logicalAddressId: logicalAddressId,
                                    serviceDomainId: serviceDomainId,
                                    serviceConsumerId: serviceConsumerId,
                                    include: "serviceContract"
                                }
                            });

    var supportedServiceContracts = [];

    cooperations.data.forEach(function(cooperation) {

        axios.get('http://api.ntjp.se/coop/api/v1/serviceProducers.json', {
                    params: {
                        connectionPointId: connectionPointId,
                        logicalAddressId: logicalAddressId,
                        serviceDomainId: serviceDomainId,
                        serviceConsumerId: serviceConsumerId,
                        serviceContractId: cooperation.serviceContract.id
                    }
        }).then(response => {

            supportedServiceContracts.push({serviceContract: cooperation.serviceContract.namespace, serviceProducerDescription: response.data[0].description, serviceProducerHSAId: response.data[0].hsaId});

        });


    });

    connectionStatus.supportedServiceContracts = supportedServiceContracts;

    sendMessage();

    function sendMessage() {

        console.log(connectionStatus); // The array supportedServiceContracts has data
        console.log(JSON.stringify(connectionStatus)); // The array supportedServiceContracts has NO data

        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.sendMessage(tabs[0].id, connectionStatus);
        });

    };

}

});

内容.js

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
    console.log(request); // The array supportedServiceContracts has NO data

});

标签: javascriptarraysobjectgoogle-chrome-extension

解决方案


  • 使用Promise.all()完成所有网络请求后发送消息- 浏览器将自动将所有请求排入队列并一次发出一堆,还有 JS 库允许自定义 Promise.all 中的并行作业数量。
  • 使用tabbrowserAction.onClicked 的参数而不是重新查询活动选项卡,这既多余又错误 - 用户可能会在您的代码运行时切换选项卡
  • 使用WebExtension polyfill以简单的方式通过 Promise/async 调用 API

browser.browserAction.onClicked.addListener(async tab => {

  // enqueue without waiting so we don't block the subsequent async code 
  const contentScriptReady = Promise.all([
    browser.tabs.executeScript(tab.id, {file: "axios.min.js"}),
    browser.tabs.executeScript(tab.id, {file: "content.js"}),
  ]);

  const connectionStatus = {};

  /* snipped */

  connectionStatus.supportedServiceContracts = await Promise.all(
    cooperations.data.map(cooperation =>
      axios.get('http://api.ntjp.se/coop/api/v1/serviceProducers.json', {
        params: {
          connectionPointId,
          logicalAddressId,
          serviceDomainId,
          serviceConsumerId,
          serviceContractId: cooperation.serviceContract.id,
        },
      }).then(response => ({
        serviceContract: cooperation.serviceContract.namespace,
        serviceProducerDescription: response.data[0].description,
        serviceProducerHSAId: response.data[0].hsaId,
      }))
    )
  );

  await contentScriptReady;
  browser.tabs.sendMessage(tab.id, connectionStatus);

});

PS 尝试修改您的代码,以便使用 Promise.all 并行调用多个 axios.get 请求,而不是等待每个请求按顺序完成。


推荐阅读