blog
blog copied to clipboard
个人技术博客,博文写在 Issues 里。
当我们开发扩展程序的时候,一般不会意识到扩展程序在无痕模式下的表现,因为基本上不会遇到什么问题。但是,我在开发划词翻译的时候,却因为无痕模式遇到了两次 bug,最终促使我好好调查一下无痕模式到底会对扩展程序产生什么影响。 在这之前,我先简单描述一下背景。我为了让划词翻译能在 PDF 文件里使用,于是将 PDF.js 的 viewer(即[https://mozilla.github.io/pdf.js/web/viewer.html](https://mozilla.github.io/pdf.js/web/viewer.html))打包进了划词翻译当中。安装划词翻译之后,在地址栏内粘贴 `chrome-extension://ikhdkkncnoglghljlkmcimlnlhkeamad/pdf-viewer/web/viewer.html` 就能看到这个 PDF 阅读器。 我第一个遇到的无痕模式的问题就跟这个 PDF 阅读器有关。2016 年的时候,有用户反馈在无痕模式(当时的称呼是“隐私模式”)里打不开 PDF 阅读器(见 [https://github.com/lmk123/crx-selection-translate/issues/164](https://github.com/lmk123/crx-selection-translate/issues/164)),在查阅了 Chrome 扩展程序的文档之后,我很快找到了解决方案:给 manifest.json 加一个新的属性 `"incognito": "split"`。 Chrome 扩展程序开发文档里对这个属性的说明文档地址是 [https://developer.chrome.com/docs/extensions/mv2/manifest/incognito/](https://developer.chrome.com/docs/extensions/mv2/manifest/incognito/)。简单点说,扩展程序在无痕模式下有两种运行模式: - 默认的模式是...
疫情期间公司还是照常面试,只不过现场面试改为了视频面试。 今天面试的候选人前期问题都回答的挺不错的,我心想总算碰到一个能过二面的了,但到后面我发现有些不对劲。 首先是候选人的眼睛一直在到处瞟,刚开始我没在意,但后来我注意到他总是会瞟一下屏幕的左侧(也就是他的屏幕的右侧);另外,在写函数继承的代码的时候,他很流畅的写出来了,一点问题都没有,但我问他代码里用到的 `Object.create()` 方法是干嘛的,他回答说是用来浅复制一个对象的。我就觉得不对劲了,代码写的这么流畅,可是却不理解自己写出来的代码,这是提前背好了答案吗? 然后我就开始更加留意他在视频里的表现了,果然又注意到一个情况:他脸上的电脑屏幕反光时暗时亮,很明显电脑屏幕上一直在显示一些内容。在意识到他可能有作弊的情况之后,我又回想了他之前答题的情况,发现有的问题他答得很快,但有的问题他似乎不太确定,总是会在思考半分钟左右才会给出答案,且答案是正确的。 为了验证我的猜想,我又问了他一个问题:“JavaScript 如何读取浏览器的 cookies?” 他先是回答“好像有一个 `document.getCookies()` 方法”,过了一会儿之后,又突然改口说“直接读取 document.cookies 就行”,我注意到在回答问题的期间,他脸上的电脑反光又明暗交替的闪了几下,而且我隐约听见了鼠标点击的声音。 心里有了底气之后,我决定直接问他,于是我说:“我有个疑问,我发现你脸上的电脑反光一直时暗时亮,而且你的眼睛时不时的会往屏幕左边瞟,这是怎么回事?” 候选人明显没有预料到我会直接跟他对峙,在听到一声微小的鼠标点击的声音后,他脸上的亮光立刻就没了——很显然,他关闭了显示器里发亮的窗口。之后他坐起了身子解释道:“呃我刚才一直把公司群放在右边,因为我怕错过公司里的消息,所以时不时的看一下。” 这解释也太不符合常理了——候选人应该已经离职了,因为在面试开始时我听到他接了一个电话,他说“周五上午 11 点可以吗”,明显是有公司在跟他约面。今天才周二,难道他是请了四天的假,或者他是打算周五再请个假? 就算是这样,也没有人会一边工作一边面试吧?如果真有紧急的事情需要时时盯着,为什么不申请更改面试的时间? 我没有直接戳破他,而是又随便写了点代码,就跟他说面试结束,七个工作日内给答复之类的,言外之意其实就是面试没通过,他的反应很干脆,一点也不像其他候选人那样觉得遗憾或不解之类的,更让我觉得他心里有鬼。 之前就有同事跟我说,北京那边面试作弊的情况很严重,今天我信了 :joy:
最近上线了截图翻译的功能,大致流程就是在前端页面截图后,调用某云的 OCR 接口将截图转成文字然后翻译。但是,使用某云的接口需要用户自行申请,这对普通用户来说很不方便,于是就想找找看有没有能直接在浏览器里使用的文字识别工具,然后就发现了 [Tesseract.js](https://tesseract.projectnaptha.com/)。 我本来以为,有了它就可以代替 OCR 接口了,但使用之后发现是我想多了。 > 以下使用感受来自一台 8 核 3.6 GHz、16 GB 内存的 Windows 电脑。 ### 识别速度慢 我使用了 8 个 worker、每个 worker 都只加载了英语的数据包,识别一张 300 x 100 像素的截图需要 4...
如果你想知道划词翻译是怎么开发出来的,可以阅读一下。 **不需要有开发扩展程序的经验即可读懂,但是需要了解基本的前端开发(HTML、CSS、JavaScript)技术。** 地址:https://github.com/lmk123/how-to-build-hcfy
在[《离线数据同步的具体实现思路》](https://github.com/lmk123/blog/issues/83)一文中,我实现了第一个版本的离线数据同步功能,最近在实际项目中应用了这个实现,又想到了一些改进的点。 ## 上传本地数据库变更与下载服务器数据库变更应该分开 在之前的实现当中,同步数据的方法有且只有 `sync`,这个方法先是提交了本地数据库的变更,然后又下载了服务器数据库的变更并保存到本地数据库。但在实际场景中,上传与下载很有可能是分开的。 这一点是受到了 iPhone 的“备忘录”的启发。当我在网页版的备忘录 [https://www.icloud.com/notes/](https://www.icloud.com/notes/) 里编辑我的备忘录之后,然后在手机里打开备忘录时,我首先看到的是我在网页版编辑之前的内容,然后备忘录会开始检查更新,大约 1 秒后内容就变成了我在网页版编辑之后的内容。 所以,我们应该把 `sync` 一分为二成为两个方法 `commit` 和 `pull`: - `commit`:将本地数据库的变更提交到服务器。例如,每当用户新增一条待办事项之后,就执行一次 commit - `pull`:将服务器数据库的变更保存到本地数据库。例如,当用户打开待办事项列表之后,我们先显示本地数据库的数据,然后执行一次 `pull` 将服务器变更保存到本地数据库中,并更新用户的 UI `pull` 方法也会下载到由自己提交的本地数据库变更,所以在把服务器数据库变更保存到本地时,还需要检查一下这些变更里面有哪些数据已经存在于本地数据库了。 ## 变更记录的删除时机...
我最近要做一个离线数据同步的的功能,这次把我的实现过程记录下来。 ## 场景 一个待办事项 APP,可以离线使用、支持多个端,要求是多个端的数据都是同步的。 ## 大致思路 - 用户登录时,从服务器下载全部数据到客户端。 - 之后用户在客户端增删改数据时,把每种操作都记录下来;等到上传本地变更的时候,收集所有改动并发送到服务器,服务器将这些改动应用到数据库的同时,再用另一张表记录这些变更; - 更新数据时,本地客户端将上次更新数据的时间(至少也是第一次完全下载数据的时间)发送给服务器,服务器返回此时间节点后的所有变更给客户端。 按照这个思路,我们就可以把示例代码写出来了: ```typescript async function sync() { // 读取上次同步数据的时间 let lastSyncTime: number | undefined = getLastSyncTime() // 用户登录之后,这个时间肯定是没有的,所以此时需要从服务器下载完整数据...
最近要做一个数据同步的功能,先介绍一下类似的场景: 假设我有一个待办事项 APP,同时支持网页端、移动端和桌面端,功能就是待办事项清单,用户可以在任意端新增、修改、删除待办事项,其他端都要同步到数据。 ## 第一个想法:完全从数据库读取数据 这应该是最常见的做法了:无论从哪个端打开待办事项,都从服务器加载数据;对待办事项的新增、修改、删除操作都在服务器的数据库进行,本地不保存任何数据。 但这种模式有一个缺点:APP 没办法离线使用了。对于一个待办事项 APP 而言,用户应该是无需登录就可以使用的。 ## 第二个想法:判断操作是在哪个端进行的,然后下载新增的数据 先给用户登录过的每个端都生成一个唯一的设备 id 进行区分。然后,当用户在其中一个端 A 新增待办事项之后,先在本地数据库新增,然后将这次新增的数据提交到服务器,且标识是由端 A 新增的;当用户从别的端 B 打开 APP 时,就从服务器查询数据库,找到不是由端 B 新增的数据,然后保存到端 B 的本地数据库。 但是……这个办法只能找到新增的数据,对修改和删除操作无效。 ## 第三个想法:记录用户的操作...
上午写了一个小模块,想发布到 npm 里。网上查了查资料,发现发布模块很简单: ``` npm login npm publish ``` 结果这两步花了我两小时。 当我运行`npm login`的时候,它老是提示我用户名或密码不正确,我就纳闷了:我自己在 [npmjs.com](https://www.npmjs.com/) 上登录了好多次了,为嘛在命令行里就会错误? 这时我发现下面有个提示: ``` npm ERR! You may need to upgrade your version of npm: npm ERR! npm...
最近正在用 React 开发新版划词翻译,在调试上遇到了不小的麻烦。 普通的网站项目可以直接安装 React Devtools 提供的浏览器扩展进行调试,但是划词翻译本身就是一个扩展程序,而扩展程序相互之间是访问不到执行环境的,所以我自然也没法用 React Devtools 扩展程序调试划词翻译里的 React 代码。 我本来以为这是没办法解决的,所以只好用 Chrome 开发者工具调试代码,但随着代码逻辑越来越复杂,这样的调试方式就越来越痛苦了—— 直到我无意中发现,CodeSandbox 这个网站把 React Devtools 嵌入到网页中去了(见 https://codesandbox.io/s/dk9gj),也就是说,我应该也可以把 React Devtools 嵌入到我的扩展程序中来调试代码! 本来以为我可以造个小轮子了,但没想到官方早就解决了这个问题 :joy: React Devtools 其实有三种使用形式: -...
今天用 Node.js 写了一段代码,但是却遇到了一个问题。 这段代码本身很简单,就是从网络上下载一个 zip 文件,然后读取 zip 中一个文件的内容,代码一共就 20 行: ```js const fetch = require('node-fetch') const unzipper = require('unzipper') ;(async () => { const response = await fetch('http://a.domain/some.zip') if (response.ok)...