当前位置: 首页 > news >正文

Electron系列文章-主进程与渲染进程

本文主要讲解上一章节提到的主进程与渲染进程的概念,以及它们是如何被使用的

如果对文章的内容有任何疑问或吐槽,请直接在下方评论,大家共同学习和改进

阅读时间:约4min

主进程与渲染进程

我们来回顾一下,程序目录结构章节中所给出的基本目录结构

app----------------------------应用程序代码目录
├─main.js----------------------程序启动入口,主进程
├─common-----------------------通用模块
├─log--------------------------日志模块
├─config-----------------------配置模块
├─ipc--------------------------进程间模块
├─appNetwork-------------------应用通信模块
└─browserWindows---------------窗口管理,渲染进程
    ├─components---------------通用组件模块
    ├─store--------------------数据共享模块
    ├─statics------------------静态资源模块
    └─src----------------------窗口业务模块
        ├─窗口A----------------窗口
        └─窗口B----------------窗口
复制代码

在上面的目录结构中,main.js就是我们所说的主进程。而通过browserWindows目录下窗口文件创建的进程,我们称之为渲染进程。渲染进程需要通过主进程来创建,并被主进程所管理。这里大家可能会有疑问了,什么是进程?为什么要分主进程和渲染进程呢?

进程的概念

计算机进程相关的知识在搜索引擎中可以搜到很多,我们这里不做过多的讲解。读者可以把进程理解为操作系统管理应用程序的基本单位,每个进程之间的资源是不能直接共享的。打开操作系统的任务管理器,我们可以看到当前操作系统都有那些进程,如下图

主进程

回顾以往的web开发,我们的代码,无论是HTML、CSS还是Javascript,都是运行在浏览器的沙盒中的,我们无法越过浏览器的权限访问系统本身的资源,代码的能力被限制在了浏览器中。浏览器之所以这么做,是为了安全的考虑。设想一下,我们在使用浏览器的时候,会打开各式各样不同来源的网站,如果JavaScript代码有能力访问并操作本地操作系统的资源,那将是多么可怕的事情。你在某天不小心打开了一个恶意的网站,可能你存储在硬盘上的文件就被偷走了(都用不着去修电脑)。

但我们要开发的是桌面应用程序,如果无法访问到本地的资源肯定是不行的。Electron将nodejs巧妙的融合了进来,让nodejs作为整个程序的管家。管家拥有较高的权限,可以访问和操作本地资源,使用原本在浏览器中不提供的高级API。同时管家也管理着渲染进程窗口的创建和销毁。所以,我们将这个管家称之为主进程。在使用Electron开发的程序中,会使用main.js作为程序的主入口,该文件内代码执行的内容,就是主进程中执行的内容。

下面我们一起来看看主进程中一般都做些什么。

//main.js

var electron      = require('electron');
var app           = require('electron').app;

//初始化
app.on('ready', function(){

    try{      
        //app ready
    }catch(err){
        log.error(err);
    }
});

复制代码

上面是一个最简单的main.js例子。在例子中,我们首先引入了electronelectron.app模块。electron.app对象控制着整个程序的生命周期,在这我们只注册了生命周期中的ready事件,当ready事件被触发的时候,表示整个程序已经初始化完毕,可以开始进行创建窗口等业务逻辑了。

在现实的应用中,主进程的代码远比上面的例子复杂的多。有许多需求特性的实现都是在主进程中完成,下面举个例子进行讲解。

程序互斥

在某些场景中,应用程序被要求在系统中只能同时开启一个。所以当某个应该已经在系统中运行时,如果再次双击应用icon,程序应该将自己退掉,或者是把之前打开的程序退掉。

(function(){

  app.makeSingleInstance(singleInstanceCallBack);

  function singleInstanceCallBack(commandLine, workingDirectory){

    console.log('command line: ', commandLine);
    console.log('working directory: ', workingDirectory);

    app.exit(0);        
  }
})();

复制代码

这里使用的是app.makeSingleInstanceapi实现的这个功能。singleInstanceCallBack函数是当第二个实例启动时,第一个实例执行的回调,所以singleInstanceCallBack里面使用的app实际上指向的是先打开的实例(刚接触这个api的时候确实有点绕),上面的代码中,singleInstanceCallBack执行时,调用了app.exit方法退出了先打开的程序。那我们如何去判断当前是第二个实例呢?其实,makeSingleInstance的返回值是一个boolean类型的值,为true时表示当前是第二个实例。如果需求是想让第二个实例退出,则在当前的作用域中直接调用app.exit即可。

渲染进程

Electron集成了Chromium来展示窗口界面,窗口中所看到的内容使用的都是HTML渲染出来的。 Chromium本身是多进程渲染页面的架构(在默认情况下,Chromium的默认策略是对每一个tab新开一个进程,以确保每个页面是独立且互不影响的。避免一个页面的崩溃导致全部页面无法使用),所以Electron在展示窗口时,也会使用到Chromium的多进程架构。而这种多进程渲染架构在Electron中,就被称之为渲染进程(render process)。

在Electron中,每创建一个新的窗口,都是一个独立的进程。

//main.js
const {BrowserWindow} = require('electron');
const window1 = new BrowserWindow({width: 200, height: 200})
const window2 = new BrowserWindow({width: 200, height: 200})

window1.loadURL('https://baidu.com');
window2.loadURL(`file://${__dirname}/index.html`)

复制代码

在上面的代码中,我们创建了2个窗口,window1window2。这两个窗口就是互相独立的进程。window1窗口内容指向的是百度首页,window2窗口内容指向的是我们自己开发的html页面。在index.html中,我们可以像开发正常的web网页一样,开发窗口内容。以下是index.html的一个示例

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,user-scalable=0">
    <title>main page</title>
</head>
<body>
    <div id="app">Hello World</div>
    <script type="text/javascript" src="mainPage.js"></script>
</body>
</html>
复制代码

在介绍主进程的篇幅中,我们说到只有主进程才有获取本地资源的权限。实际场景中,有时需要将主进程中获取的本地数据在窗口中展示出来,该怎么实现呢?

在下一章,我们会重点讲解主进程与渲染进程之间如何通信的知识。

转载于:https://juejin.im/post/5c9041205188252d9c5bae83

相关文章:

  • 刀塔自走棋上线不到十分钟就被功击,几十万玩家登录不上
  • java内存占用异常问题常见排查流程(含堆外内存异常)
  • Java springcloud B2B2C o2o多用户商城 springcloud架构(八)springboot整合mongodb
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 云端服务器与传统的独立主机服务器有什么区别
  • 中台之上(十三):探讨支持组装式开发的业务架构设计方法
  • 阿里CTO:阿里所有技术和产品输出都将必须通过阿里云进行
  • python -迭代器与生成器 以及 iterable(可迭代对象)、yield语句
  • LeetCode.914 卡牌分组
  • 本周学习小结(25/03 - 31/03)
  • Beetl 提供俩种方式来显示实现局部更新
  • core_framework —— 基于libev的轻量级lua网络开发框架
  • MyCAT水平分库
  • 织梦CMS模板中dede标签使用php和if判断语句的方法
  • 2019第十四届中国竞争情报国际年会将于4月在上海召开
  • [译] React v16.8: 含有Hooks的版本
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • chrome扩展demo1-小时钟
  • CSS 专业技巧
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • java小心机(3)| 浅析finalize()
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • Linux链接文件
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • VUE es6技巧写法(持续更新中~~~)
  • 工程优化暨babel升级小记
  • 关于for循环的简单归纳
  • 力扣(LeetCode)965
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 网页视频流m3u8/ts视频下载
  • 一天一个设计模式之JS实现——适配器模式
  • 译自由幺半群
  • 用jQuery怎么做到前后端分离
  • 1.Ext JS 建立web开发工程
  • Java数据解析之JSON
  • linux 淘宝开源监控工具tsar
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​虚拟化系列介绍(十)
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #includecmath
  • #宝哥教你#查看jquery绑定的事件函数
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (bean配置类的注解开发)学习Spring的第十三天
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (floyd+补集) poj 3275
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (八)Spring源码解析:Spring MVC
  • (第二周)效能测试
  • (篇九)MySQL常用内置函数
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (算法设计与分析)第一章算法概述-习题
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...