简体   繁体   English

传递时对象中的数组为空或 JSON.stringified

[英]Array in object empty when passed or JSON.stringified

I'm creating a Chrome Extension where I'm sending an object (connectionStatus) from a background script to a content script.我正在创建一个 Chrome 扩展,我将一个对象(connectionStatus)从后台脚本发送到一个内容脚本。 The object contains an array (supportedServiceContracts), which is empty when I log the object in content.js even though I can see it has data when I log it in background.js just before I send it.该对象包含一个数组 (supportedServiceContracts),当我在 content.js 中记录对象时该数组为空,即使我在发送它之前在 background.js 中记录它时我可以看到它有数据。

Why is that?这是为什么?

UPDATE:更新:

I should also mention that the array part of the object gets empty if I apply JSON.stringify() on the object.我还应该提到,如果我在对象上应用JSON.stringify() ,对象的数组部分会变空。 See screenshot.见截图。

在此处输入图片说明

background.js背景.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内容.js

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

}); });

  • Send the message after completing all network requests by using Promise.all() - the browser will automatically enqueue all the requests and emit just a bunch at once, also there are JS libraries that allow customizing the amount of parallel jobs in Promise.all.使用Promise.all()在完成所有网络请求后发送消息 - 浏览器将自动将所有请求排入队列并一次发出一堆,还有 JS 库允许在 Promise.all 中自定义并行作业的数量。
  • Use the tab parameter of browserAction.onClicked instead of requerying the active tab, which is both redundant and wrong - the user may switch tabs while your code is working使用 browserAction.onClicked 的tab参数而不是重新查询活动选项卡,这既多余又错误 - 用户可能会在您的代码工作时切换选项卡
  • Use the WebExtension polyfill to call the API with Promise/async in a straightforward fashion使用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 Try reworking your code so that several axios.get requests are invoked in parallel by using Promise.all instead of waiting for each one to complete sequentially. PS 尝试重新编写代码,以便使用 Promise.all 并行调用多个 axios.get 请求,而不是等待每个请求按顺序完成。

Try adding to the array inside the .then function:尝试添加到 .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);
    });
};

Or use the async-await pattern you use elsewhere...或者使用你在其他地方使用的异步等待模式......

The array you have declared supportedServiceContracts is still empty when the method sendMessage() was called.调用方法sendMessage()时,您声明的supportedServiceContracts数组仍为空。 This is because the line with the supportedServiceContracts.push(...) is inside a Promise callback function.这是因为带有supportedServiceContracts.push(...)的那一行在Promise回调函数中。 By the time sendMessage() is called, not even at least one of the API request promise is resolved which means nothing has been pushed to the supportedServiceContracts yet.到调用sendMessage() ,甚至没有至少一个 API 请求承诺得到解决,这意味着还没有任何内容推送到supportedServiceContracts

You will have to:你不得不:

  1. Wait for all the individual request that pushes values to supportedServiceContracts等待所有将值推送到supportedServiceContracts的单个请求
  2. Then you are safe to call sendMessage() AFTER the requests are resolved.然后您可以安全地在请求解决后调用sendMessage()

One way to do this is to make use of Promise.all() which will make you a Promise that will resolve after all the promises passed as an array have resolved.一种方法是使用Promise.all() ,这将使您成为一个 Promise ,该 Promise 将在作为数组传递的所有 Promise 都已解决后解决。 You can call sendMessage() in the callback function of your Promise.all()您可以在Promise.all()的回调函数中调用sendMessage() Promise.all()

Example:例子:

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

Please try to make something similar with this as this is just a pseudo code and might not work directly if you copy paste only.请尝试制作与此类似的东西,因为这只是一个伪代码,如果您仅复制粘贴,则可能无法直接使用。 This is only theoretical and written directly here without any tests.这只是理论上的,直接写在这里,没有任何测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM