一个Electron的设计缺陷及应对方案
当你想实现阻止Electron窗口关闭,并弹出询问对话框,提示用户:“文章尚未保存,是否要关闭窗口”这类业务时,那么你99%会碰到这个BUG:
https://github.com/electron/electron/issues/24994
这是我在去年8月份发现的BUG,Electron的作者也已经确认了这个BUG,但遗憾的是现在还没有修复。下面我们就聊聊这个问题,以及应对这个问题的方案。
问题描述
要阻止窗口关闭,必须在窗口的关闭事件中,执行preventDefault操作才行,如下代码所示:
win.on("close", (e) => {
e.preventDefault();
});
然而这个preventDefault的操作,必须同步调用才能生效,所有异步调用preventDefault的操作都没有任何效果,代码如下所示:
win.on("close", async (e) => {
console.log("win close");
await new Promise((resolve) => setTimeout(resolve, 1000));
e.preventDefault(); //没有任何作用
});
上述代码中的preventDefault操作就不会起任何作用。这就带来了一个业务问题:我们往往在询问用户并获得用户的允可后才会阻止窗口关闭,比如:“文章尚未保存,您确认关闭窗口吗?”开发者无法在这种异步的询问通知前执行preventDefault操作,就无法正确的阻止窗口关闭。
可能你会想到用dialog模块的showMessageBoxSync方法来完成这个询问操作,如下代码所示:
win.webContents.on('will-prevent-unload', event => {
let choice = dialog.showMessageBoxSync({
title:'do you want to close',
buttons:['cancel','yes']
});
if(choice === 1) event.preventDefault();
//...
})
没错showMessageBoxSync是一个同步方法,但这也会导致整个主进程的JavaScript线程阻塞,你预期在未来发生的所有事件,以及这些事件的回调方法,都不会再执行了(想想看,你的setInterval的回调方法不会定时执行的结果)。
直到用户关闭showMessageBoxSync方法打开的窗口,主进程的JavaScript线程才会恢复,如果用户永远不做出这个选择,那么整个JavaScript线程就会一直等待下去。
应对方案
为了解决这个问题,我们可以通过额外的哨兵变量来处理,代码如下所示:
//import { app, BrowserWindow, dialog } from "electron";
let winCanBeClosedFlag = false;
win.on("close", async (e) => {
if (!winCanBeClosedFlag) {
e.preventDefault();
let choice = await dialog.showMessageBox(win, {
title: "do you want to close",
message: "你确定要关闭窗口吗?",
buttons: ["否", "是"],
});
if (choice.response == 1) {
winCanBeClosedFlag = true;
win.close();
return;
}
}
winCanBeClosedFlag = false;
});
默认情况下winCanBeClosedFlag 这个变量的值是false,即不允许用户关闭窗口(此处的preventDefault是同步操作),当我们询问过用户,并且用户做出了确认关闭的选择后,这个变量才会被设置为true。此时立即调用窗口的close方法,这个窗口的close事件被再次触发,因为winCanBeClosedFlag 变量已经被置为true了,所以不会执行preventDefault操作,窗口被正常关闭。
窗口被关闭的同时winCanBeClosedFlag变量又被置为false,以备下一次用户的操作。
一个Electron的设计缺陷及应对方案的更多相关文章
- 转:Javascript的10个设计缺陷
作者: 阮一峰 日期: 2011年6月30日 前几篇文章,我经常说Javascript的设计不够严谨,有很多失误. 今天的这一篇,前半部分就谈为什么会这样,后半部分将列举Javascript的10个设 ...
- Java高并发的常见应对方案
Java高并发的常见应对方案 一.关于并发我们说的高并发是什么? 在互联网时代,高并发,通常是指,在某个时间点,有很多个访问同时到来. 高并发,通常关心的系统指标与业务指标? QPS:每秒钟查询量,广 ...
- 谷歌启用抓取JavaScript,应对方案!
谷歌启用了抓取JavaScript来深入了解网站,这样,如果网站或黑页是加了跳转代码或判断代码,很有可能将会被识别出来.虽然目前只是谷歌启用识别JavaScript文件,但国内搜索引擎很可能也会跟着模 ...
- MySQL性能调优与架构设计——第 17 章 高可用设计之思路及方案
第 17 章 高可用设计之思路及方案 前言: 数据库系统是一个应用系统的核心部分,要想系统整体可用性得到保证,数据库系统就不能出现任何问题.对于一个企业级的系统来说,数据库系统的可用性尤为重要.数据库 ...
- 为什么Javascript有设计缺陷
1. 设计阶段过于仓促 Javascript的设计,其实只用了十天.而且,设计师是为了向公司交差,本人并不愿意这样设计(参见<Javascript诞生记>). 另一方面,这种语言的设计初衷 ...
- .Net开发笔记(十九) 创建一个可以可视化设计的对象
阅读本篇博客之前需要了解VS窗体设计器的工作原理,详细可参见本系列博客(十).(十一).(十二).必须需要知道的一条结论就是:处于窗体设计器(Form Designer)中的任何组件(包含控件,下同) ...
- Android4.0 Design之UI设计缺陷1
我想成为Android卓越发展project联赛,不知道Android它如何设计规则,Android4.0谷歌公司的问世后Android一系列的设计原则,程序猿规范,不要盲目模仿IOS它的设计,由于A ...
- 一个RtspServer的设计与实现和RTSP2.0简介
一个RtspServer的设计与实现和RTSP2.0简介 前段时间着手实现了一个RTSP Server,能够正常实现多路RTSP流的直播播放,因项目需要,只做了对H.264和AAC编码的支持,但是 ...
- SSLv3存在严重设计缺陷漏洞(CVE-2014-3566)
SSLv3存在严重设计缺陷漏洞(CVE-2014-3566) 1.引发问题的原因 SSLv3漏洞(CVE-2014-3566),该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等 ...
随机推荐
- java web课程设计(简单商城的前后端双系统,基于maven三模块开发)
1.系统分析 1.1需求分析 实现一个简单但功能完整的商城项目,从设计到实现,规范化完成该项目,锻炼javaweb项目的编写能力,理解软件工程的软件设计思想 1.2编程技术简介 本次课程主要使用的软件 ...
- 使用dom4j工具:xml总结
1.IO流:BufferedReader字符流readLine();截取 不可行!!!2.XML解析:dom4j查:标签:element("name")elements(" ...
- rabbitMq可靠性投递之手动ACK
#手动应答#spring.rabbitmq.listener.simple.acknowledge-mode=manual#spring.rabbitmq.listener.simple.acknow ...
- ES6两种静态属性的书写方法
1.这种可以不用实例化对象就能输出. class Car{ constructor(){ } } Car.tool=4 console.log(Car.tool);//4 2.必须实例化后才能输出.但 ...
- PowerDotNet平台化软件架构设计与实现系列(01):基础数据平台
本系列我将主要通过图片和少许文字讲解通过个人自研的PowerDotNet进行快速开发平台化软件产品. PowerDotNet不仅仅是包含像Newtonsoft.Json.Dapper.Quartz.R ...
- 博观约取系列 ~ 探测Bert Finetune对向量空间的影响
熟悉NLP的同学对Bert Finetune一定不陌生,基本啥任务上来都可以Bert Finetune试一把.可是模型微调一定比直接使用预训练模型效果好么?微调究竟对Bert的向量空间产生了哪些影响嘞 ...
- 前后端数据交互(二)——原生 ajax 请求详解
一.ajax介绍 ajax 是前后端交互的重要手段或桥梁.它不是一个技术,是一组技术的组合. ajax :a:异步:j:js:a:和:x:服务端的数据. ajax的组成: 异步的 js 事件 其他 j ...
- 记一次线上问题 → 对 MySQL 的 ON UPDATE CURRENT_TIMESTAMP 的片面认知
开心一刻 老婆痛经,躺在沙发上,两岁的女儿看着她问道 女儿:妈妈,你怎么了 老婆:妈妈肚子痛 女儿:哦,妈妈你头疼 老婆:不是头疼,妈妈是肚子疼 女儿用她的不锈钢饭碗砸向老婆的额头,说道:妈妈,你哪里 ...
- Django——实现评论功能(包括评论回复)
提示:(1)功能不全面,仅仅实现评论(2)样式简单 1.项目目录结构 2.模型 from django.db import models from django.contrib.auth.models ...
- MySQL实战45讲(01--05)-笔记
目录 MySQL复习 01 | 基础架构:一条SQL查询语句是如何执行的? 连接器 查询缓存 分析器 优化器 执行器 02 | 日志系统:一条SQL更新语句是如何执行的? 重要的日志模块:redo l ...