【问题标题】:Tips on solving 'DevTools was disconnected from the page' and Electron Helper dies解决“DevTools 与页面断开连接”和 Electron Helper 死机的提示
【发布时间】:2019-07-28 15:46:06
【问题描述】:

我在使用 Electron 时遇到了应用程序空白的问题。即它变成一个白屏。如果我打开开发工具,它会显示以下消息。

在 ActivityMonitor 中,我可以看到 Electron Helper 进程的数量从 3 个下降到 2 个。另外,似乎我不是唯一遇到它的人。例如

但我还没有找到有帮助的答案。在 Electron 崩溃的情况下,有什么好的方法可以识别问题吗?

对于上下文,我将 sdk 加载到 Electron 中。最初我使用 browserify 来打包它,效果很好。但我想转到 SDKs npm 版本。这个版本好像引入了问题(虽然代码应该是一样的)。

【问题讨论】:

  • 检查你的终端有没有错误?
  • 没有。我试图捕捉 uncaughtException 和 SIGTERM 但这些处理程序没有被触发。
  • 能否提供一些代码或代码链接?
  • 我无法确定是代码的哪一部分导致了问题。因此,我无法提供代码的精简版本。目前它只是我本地机器上的一个原型。

标签: debugging electron freeze


【解决方案1】:

自从我最初发布这个问题以来,已经过去了很长时间。我会自己回答,以防我的错误可以帮助任何人。

我从来没有得到原始问题的“解决方案”。很久以后,我切换到 sdk 的 npm 版本,它工作了。

但在那之前,我会再次遇到这个问题。幸运的是,到那时,我已经添加了一个记录器,它也将控制台写入文件。有了它,我注意到 JavaScript 语法错误导致了崩溃。例如缺少右括号等。

我怀疑这是导致我最初的问题的原因。但是 Chrome 开发工具做的最糟糕的事情是在工具崩溃时使控制台空白而不是保留它。

我用来设置记录器的代码

/*global window */
const winston = require('winston');
const prettyMs = require('pretty-ms');

/**
 * Proxy the standard 'console' object and redirect it toward a logger.
 */
class Logger {
  constructor() {
    // Retain a reference to the original console
    this.originalConsole = window.console;
    this.timers = new Map([]);

    // Configure a logger
    this.logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.printf(({ level, message, timestamp }) => {
          return `${timestamp} ${level}: ${message}`;
        })
      ),
      transports: [
        new winston.transports.File(
          {
            filename: `${require('electron').remote.app.getPath('userData')}/logs/downloader.log`, // Note: require('electron').remote is undefined when I include it in the normal imports
            handleExceptions: true, // Log unhandled exceptions
            maxsize: 1048576, // 10 MB
            maxFiles: 10
          }
        )
      ]
    });

    const _this = this;

    // Switch out the console with a proxied version
    window.console = new Proxy(this.originalConsole, {
      // Override the console functions
      get(target, property) {
        // Leverage the identical logger functions
        if (['debug', 'info', 'warn', 'error'].includes(property)) return (...parameters) => {
          _this.logger[property](parameters);
          // Simple approach to logging to console. Initially considered
          // using a custom logger. But this is much easier to implement.
          // Downside is that the format differs but I can live with that
          _this.originalConsole[property](...parameters);
        }
        // The log function differs in logger so map it to info
        if ('log' === property) return (...parameters) => {
          _this.logger.info(parameters);
          _this.originalConsole.info(...parameters);
        }
        // Re-implement the time and timeEnd functions
        if ('time' === property) return (label) => _this.timers.set(label, window.performance.now());
        if ('timeEnd' === property) return (label) => {
          const now = window.performance.now();
          if (!_this.timers.has(label)) {
            _this.logger.warn(`console.timeEnd('${label}') called without preceding console.time('${label}')! Or console.timeEnd('${label}') has been called more than once.`)
          }
          const timeTaken = prettyMs(now - _this.timers.get(label));
          _this.timers.delete(label);
          const message = `${label} ${timeTaken}`;
          _this.logger.info(message);
          _this.originalConsole.info(message);
        }

        // Any non-overriden functions are passed to console
        return target[property];
      }
    });
  }
}

/**
 * Calling this function switches the window.console for a proxied version.
 * The proxy allows us to redirect the call to a logger.
 */
function switchConsoleToLogger() { new Logger(); } // eslint-disable-line no-unused-vars

然后在 index.html 我首先加载这个脚本

<script src="js/logger.js"></script>
<script>switchConsoleToLogger()</script>

【讨论】:

    【解决方案2】:

    我安装了 Google Chrome 版本 79.0.3945.130(64 位)。每次我处于调试模式时,我的应用程序都会崩溃。我尝试了在网上找到的所有解决方案,但没有一个有用。我降级到所有以前的版本:

    1. 78.x 崩溃
    2. 77.x 崩溃
    3. 75.x 未崩溃

    我不得不重新安装版本 75.0.3770.80(64 位)。问题已解决。这可能是新版本的 Chrome 问题。我向 Chrome 帮助发送了反馈。

    【讨论】:

    • 对我来说也是如此:在使用断点进行调试时,Google Chrome 80.0.3987.87(64 位)总是在同一点崩溃。改为安装 Google Chrome 75.0.3770.100(64 位)-> 已修复。
    【解决方案3】:

    调试这样的崩溃的诀窍是启用日志记录,这在默认情况下显然是禁用的。这是通过设置环境变量ELECTRON_ENABLE_LOGGING=1 来完成的,如this GitHub issue 中所述。

    启用该功能后,您应该会在控制台中看到与此类似的内容:

    【讨论】:

      【解决方案4】:

      我的问题是我没有加载像index.html 这样的页面。一旦我加载问题就消失了。

        parentWindow = new BrowserWindow({
          title: 'parent'
        });
        parentWindow.loadURL(`file://${__dirname}/index.html`);
        parentWindow.webContents.openDevTools();
      

      【讨论】:

        【解决方案5】:

        您可以下载 Google Chrome Canary。我在 Google Chrome 上遇到了这个问题,DevTools 每次都在同一个地方崩溃。在 Chrome Canary 上,调试器不会崩溃。

        【讨论】:

          【解决方案6】:

          我也遇到了同样的问题

          我试图从渲染器端要求 sqlite3 模块 这导致了一个问题,但是一旦我删除了请求,它就可以正常工作了

          const {app , BrowserWindow , ipcMain, ipcRenderer } = require('electron')
          const { event } = require('jquery')
          const sqlite3 = require('sqlite3').verbose(); // <<== problem
          

          我认为解决这个问题的最好方法(如果你的代码真的很小)只是尝试删除函数并一遍又一遍地运行它,最终你可以将其缩小到核心问题

          这是一种非常乏味、愚蠢且不聪明的做法,但它确实有效

          【讨论】:

          • 我对@9​​87654323@ 也有问题,但它应该在渲染器端工作不应该吗?
          • 在函数内移动require('sqlite3') 并将该函数暴露给要从 HTML 调用的窗口似乎已经奏效。不确定这是否是首选方式。你可以在这里看到这个问题:github.com/mapbox/node-sqlite3/issues/1504
          【解决方案7】:

          我遇到了这个问题,但无法弄清楚为什么 DevTool 总是断开连接。所以一时兴起,我启动了 Firefox 开发者版,并将原因确定为具有字符串长度属性的未定义变量。

          if ( args.length > 1 ) {
              $( this ).find( "option" ).each(function () {
                  $( $( this ).attr( "s-group" ) ).hide();
              });
              $( args ).show();
          }
          

          TL;DR Firefox 开发者版可以在 Chrome 的 DevTool 出现故障时识别出这类问题。

          【讨论】:

          • 但是 Electron 不使用 Firefox。
          【解决方案8】:

          在阅读了上面的 cmets 之后,我清楚地知道至少在 Chrome 中存在一个问题,即没有显示任何故障来源的迹象。在 Firefox 中,该程序可以运行,但延迟时间很长。

          但是,正如 Shane Gannon 所说,问题的根源肯定不在浏览器中,而是在代码中:就我而言,我打开了一个while 循环没有添加相应的增量,这使得循环无限。如下例所示:

          var a = 0;
          while (a < 10) {
          
            ...
          
            a ++               // this is the part I was missing;
          }
          

          一旦纠正,问题就消失了。

          【讨论】:

          • “但正如 Shane Gannon 所说,问题的根源肯定不在浏览器中”。我没有说问题出在浏览器上。我说这是语法错误。这不太可能是浏览器问题。
          • 你说得对,这就是我想说的。我已经编辑了句子以使其清楚。
          【解决方案9】:

          我发现升级到

          • react 17.0.2
          • react-dom 17.0.2
          • react-scripts 4.0.3

          但也因为react-scripts start 被用于运行电子,它可能只是需要更新的反应脚本。

          【讨论】:

            【解决方案10】:

            好吧,我几乎要发疯了,但主要问题是电子,我意识到我注释掉了要获取的代码 (index.html)

            // 并加载应用程序的 index.html。 mainWindow.loadFile('index.html');

            检查这一面并确保您已将其包含在内。没有这个页面将变黑或无法加载。所以检查你的 index.js 看看是否有东西可以加载你的 index.html 文件:) 如果你需要更多帮助,请随时发送邮件:profnird@gmail.com

            【讨论】:

              【解决方案11】:

              从 Electron 11 降级到 Electron 8.2 在 Angular 11 - Electron - Typeorm -sqlite3 应用程序中为我工作。

              【讨论】:

                【解决方案12】:

                打开您的 google 开发控制台 (Ctrl + shift + i)。 然后按 (fn + F1) 或仅按 F1,然后滚动向下并点击恢复默认值并重新加载。

                【讨论】:

                  猜你喜欢
                  • 2019-07-26
                  • 2018-10-24
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-03-21
                  • 2017-04-29
                  • 2021-12-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多