【问题标题】:singleton with js is causing memory leak带有 js 的单例导致内存泄漏
【发布时间】:2021-08-11 14:59:03
【问题描述】:

我正在开发一个 chrome 扩展,我希望配置对象创建一次并在应用程序的所有部分之间共享。 取决于配置的第二个对象也应该创建一次并共享。 每个对象都包含承诺。

function config () {
   this.instanse = null;
   this.status = 'pending';
   this.data = defualtData;
   
   // contructor
   this.init = async () => { 
     if(this.instanse) return this.instanse;
     this.instanse = this;
     await this.loadData(); 
   }

   this.loadData = async () => { // bring data from chrome store } 
}

第二个对象如下:


function WebsitesClass (config) {
   this.instanse = null;
   this.status = 'pending';
   this.data = config.data.userProfile;
   
   // contructor
   this.init = async () => { 
     if(this.instanse) return this.instanse;
     this.instanse = this;
     await this.loadAnotherData(this.data); 
   }

   this.loadAnotherData = async () => { // bring data from chrome store; } 
}

然后我在一个文件中实例化这两个对象:


// init.js

const configObj = new Config();

export const hudConfigInit = () => {
    if (configObj.instance) return configObj;
    configObj.init();
    return configObj;
}


export const hudConfig = hudConfigInit();

const websitesObj = new WebsitesClass(hudConfig);

const hudWebsitesObjInit = () => {
    websitesObj.init();
    return websitesObj;
}

export const hudWebsites = hudWebsitesObjInit();

然后我会将创建的对象导入我的所有文件中,例如:


import {hudConfig, hudWbsites} from 'init.js';

window.inload = async() => {

 await waitFor([ hudConfig, hudWebsites ]);

   // start work here ...

}

问题是我在这个实现的某个地方遇到了一个奇怪的无限循环。

我做错了什么?对此有何建议?

编辑

我使用这个函数来确保每个函数都被正确加载:

/**
 * @summary detect when a single object finishes loading. 
 * @param {object} obj the object that we are waiting for 
 * @returns {boolean} true when the object finishes loading
 */
const finishWorking = async (obj) => {
    if (helpers.isFunction(obj.refresh)) {
        switch (obj.type) {
            case HUD_OBJECT_TYPES.hudConfig: { await hudConfig.refresh(); break; }
            case HUD_OBJECT_TYPES.hudWebsites: { await hudWebsites.refresh(hudConfig); break; }
            // case HUD_OBJECT_TYPES.hudSubscriptions: { await hudSubscriptions.refresh(hudConfig); break; }
        }
    }
    return new Promise(async (resolve, reject) => {
        while (obj.status !== workStatus.done) {
            await helpers.sleep(1000);
            // finishWorking(obj)
            /**  ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.infinite loop was here  **/

        }
        resolve(true);
    })
}

【问题讨论】:

  • "我在某个地方遇到了一个奇怪的无限循环" - 你能说得更准确些吗?是什么让您假设存在无限循环,您观察到什么?调试器说什么,它在这个循环中暂停在哪里?这与内存泄漏有什么关系?
  • 看起来您在这里混合了三种不同的方式来实现单例。摆脱所有 .instance.instanse 代码,您的 init.js 模块无论如何只会为每个类创建一个实例。
  • 为什么要导出hudConfigInit
  • 我不导出初始化,只导出对象,我想我只是对 init() 中的承诺过于谨慎
  • 我会清理实例,真的没必要

标签: javascript google-chrome-extension memory-leaks infinite-loop


【解决方案1】:

因为它是 chrome 扩展:

  1. 在弹出窗口和选项页面之间共享对象引用将为它们中的每一个创建一个副本,因为它们都是一个单独的文档。
  2. 试图在后台和其他组件之间共享对象引用会导致错误,导致这种共享是不允许的。

解决办法是:

  1. 在最顶部的背景页面上实例化对象。
  2. 使用chrome.runtime.sendMessage() 函数与该对象交互,发送正确的消息并将响应定向到正确的对象方法。

所以:

// background.js

const configObj = new Config();

chrome.runtime.onMessage(async (req, sender, sendResponse)=>{
   switch(req.type){

    case "refreshConfig" : {
          await hudConfig.refresh();
          sendResponse(hudConfig.data);
         }
    }

})

您也可以从弹出窗口或选项或内容中发送消息:


 const refreshButton = document.querySelector('#save');

refreshButton.onClick(async() => {

  chrome.runtime.sendMessage({type: "refreshConfig"}, (data) =>{

      setData(data); //data is here the object after the update.
   })
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    • 2016-01-18
    • 2012-12-13
    相关资源
    最近更新 更多