通过或JSON.stringified时对象中的数组为空

时间:2019-02-19 22:05:57

标签: javascript arrays object google-chrome-extension

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

那是为什么?

更新:

我还应该提到,如果我在对象上应用JSON.stringify(),则对象的数组部分将为空。查看屏幕截图。

enter image description here

background.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);
        });

    };

}

});

content.js

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

});

3 个答案:

答案 0 :(得分:1)

  • 使用Promise.all()完成所有网络请求后发送消息-浏览器将自动使所有请求排队,并一次发出一堆,还有一些JS库可以自定义Promise.all中并行作业的数量。
  • 使用browserAction.onClicked的tab参数而不是重新查询活动选项卡,这既多余又是错误的-用户可以在代码运行时切换选项卡
  • 使用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);

});

P.S。尝试重新编写代码,以便使用Promise.all并行调用多个axios.get请求,而不是等待每个顺序完成。

答案 1 :(得分:0)

尝试添加到.then函数内部的数组中:

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

或者使用您在其他地方使用的异步等待模式...

答案 2 :(得分:0)

调用方法supportedServiceContracts时,已声明sendMessage()的数组仍然为空。这是因为带有supportedServiceContracts.push(...)的行在Promise回调函数中。到sendMessage()被调用时,甚至没有至少一个API请求承诺被解析,这意味着还没有任何东西被推送到supportedServiceContracts

您将必须:

  1. 等待将值推入supportedServiceContracts的所有单个请求
  2. 然后,在解决请求之后,您可以安全地致电sendMessage()

执行此操作的一种方法是利用Promise.all(),这将使您成为一个Promise,它将在作为数组传递的所有promise解决后解决。您可以在sendMessage()的回调函数中调用Promise.all()

示例:

const supportedServiceContracts = [];
const apiRequestPromises= [];

cooperations.data.forEach(cooperation => {
  apiRequestPromises.push(
    axios.get('http://api.ntjp.se/coop/api/v1/serviceProducers.json', {
        params: {
            connectionPointId: connectionPointId,
            logicalAddressId: logicalAddressId,
            serviceDomainId: serviceDomainId,
            serviceConsumerId: serviceConsumerId,
            serviceContractId: cooperation.serviceContract.id
        }
    })
  );
});

Promise.all(apiRequestPromises)
  .then(responses => {
    // Populate your array first
    responses.forEach(response => {
        supportedServiceContracts.push({
            serviceContract: cooperation.serviceContract.namespace,
            serviceProducerDescription: response.data[0].description,
            serviceProducerHSAId: response.data[0].hsaId
        });
    });
    // Then do whatever you want with it
    sendMessage();
  });

请尝试与此类似,因为这只是一个伪代码,如果仅复制粘贴,可能无法直接使用。这仅是理论上的内容,无需任何测试即可直接在此处编写。