(更多…)这篇文章用来记录使用 CodeMirror 时的一些心得。
分类: js
有关 JavaScript 的技术文章和行业分析文章。
-

使用 Proxy 添加魔术属性/方法
最近在开发我厂的 QA 工具时,遇到一个问题。我需要模拟 Puppeteer 的所有方法,以便兼容原先的 JS 文件。Puppeteer 提供一个
.asElement()方法,可以把函数执行结果转换成一个伪 DOM Element(如果函数返回的就是 DOM Element 的话),然后我们就可以在 Node.js 里调用原本属于 DOM 的方法,比如.focus()。Pupputeer 会替我们完成映射和函数调用,并且返回结果。对于大部分对象来说,我只要模拟对应的属性、方法,然后用自己的函数实现功能即可。但是 DOM Element 有上百个属性和方法,手工实现一遍实在太低效了。必须寻找其它途径。
好在我之前看过 Proxy 的介绍,赶紧翻出文档和书又复习两遍,就大概知道怎么做了。
Proxy 类如其名,可以“代理”对某个对象的访问。你可以把他理解成明星的经纪人。明星成名之前都是自己处理一切事务,有了经纪人之后,大部分事务就由经纪人负责,但仍然有一些事情需要明星自己处理。
Proxy 的用法很简单,实例化时,把要代理的对象传进去,定义一下代理方法就好。
const obj = { name: 'meathill' }; new Proxy(obj, { get(target, property) { // 如果对象中有要求的属性或方法,则返回 if (property in target) { return target[property]; } // 没有的话,进行其它处理 return 'hello'; } }); obj.name // 'meathill' obj.age // 'hello' obj.sex // 'hello'接下来,比如我们访问
obj.foo,那么代理就会生效,它会先检查obj,如果这个对象上本来就有foo属性,就会返回;如果没有,则会调用我们定义的方法来处理。如此一来,我们可以定义一个 VElement 类,这个类可以实现一些特殊方法,比如
.type(str)输入,.click()点击等;然后用 Proxy 代理其它方法和属性,让对象进入插件 Context 执行。
关于如何创建具有魔法属性/方法的类,请移步阅读 使用 Proxy 创建有魔术属性/方法的类
Proxy 还有其它方法也很有用,尤其是
get对应的set,以后再介绍。大家可以自己抽空研究下。参考
- 阮一峰的 ES6
- 《深入理解 ES6》
-

WebSocket.onerror 没有错误描述
用 WebSocket 时遇到一个问题:有时候连接出错,我希望把错误描述报告给用户,方便他们排除。但是尝试了好几种方法,都无法获得错误描述。
于是只有 Google 之,发现了这个答案:https://stackoverflow.com/questions/18803971/websocket-onerror-how-to-read-error-description。原来是为了防止开发者利用 WebSocket 搞破坏,扫描特定条件下的网络,WebSocket 的 ErrorEvent 只包含一个
error,没有更进一步的描述。onclose的CloseEvent.code也只有 1006——非正常退出,这样毫无价值的信息。所以我的处理方式是:建议用户按 F12 打开开发者工具看错误信息。
-

在 WebSocket 中处理二进制文本
我厂产品中有个需求,要用 WebSocket 接收很长的一段文本。生产环境中发现,有些内容发送时会失败,经查,是服务器端进行文本转换时,特殊字符处理存在一些问题。于是决定改为直接发送二进制流,我这边也要修改。
开始以为要处理 ArrayBuffer,人工转换,后来经过一些摸索找到方法,记录一下。
const socket = new WebSocket('wss://mydomain.com/path/to/api'); socket.binaryType = 'arraybuffer'; socket.onmessage = event => { const decodedString = new TextDecoder('utf-8').decode(event.data); // go on }其实很简单,主要用到原生类 TextDecoder,并且配置 WebSocket 以二进制文档流的方式来处理返回的数据。
-

Promise 改造 child_process.exec
child_process是 Node.js 的一个内建模块,用于分裂出(spawn)一个子进程,执行一些特定操作。.exec()是它的方法,接受一个参数,即要执行的 shell 命令,然后通过回调返回结果。.exec()与.spawn()的不同之处在于,前者重在返回结果,后者则重在返回内容。所以当你需要执行一个命令,你并不关心执行过程中发生了什么,只要看到结果就好,那么就用.exec();反之,假如执行过程中产生的信息对你特别有价值,你并不是特别在意结果,就应该用.spawn()。另外,我之前在《Node.js 8 中的 util.promisify》中介绍过,Node.js 8 引入了一个新函数,位于
util模块,叫做promisify(),用于将回调风格的 Node.js 函数改造成 Promise 规范的函数。OK,背景知识介绍结束。近期开发中,我需要执行一个命令,并且取得它的
stdout,stderr和exit code,使用promisify()之后发现没有exit code,于是只好重新写了一下,代码如下:import {exec as BaseExec} from 'util'; function exec(command, options) { return new Promise((resolve, reject) => { let result = {}; const cp = baseExec(command, options, (err, stdout, stderr) => { if (err) { err.stdout = stdout; err.stderr = stderr; reject(err); return; } result.stdout = stdout; result.stderr = stderr; if ('code' in result) { resolve(result); } }); cp.on('exit', (code, signal) => { result.code = code; result.signal = signal; if ('stdout' in result) { resolve(result); } }); }); }
希望对大家有用。
新键盘到了,FC660C,静电容,试用一下,效果还不错。略硬,段落感不强,声音不大。
-

表单元素 disabled 的判定
测试需求,判定表单元素是否 disabled。
看起来很简单,直接在浏览器控制台里用
$('input[type="text"])选中一个<input>,验证一下它的disabled属性,没问题,于是就直接写成:function isDisabled(element) { return element.disabled; }后来做到一个用户权限的功能,某一类用户,可以看到某些设置,但不能改。为了省事,就直接 禁用这部分表单。同时,因为我们用
<fieldset>包装表单元素,于是我就把disabled加在<fieldset>上,这样可以不需要修改每个元素。结果测试的时候就失败了,JS 认为这些元素不是 disabled,但视觉上和操作上它们的确被禁用了。于是调试,发现这些元素的
disabled的确为false,但是它们可以.matches(':disabled'),Google 之,StackOverflow 的几个问答也是同样的结果。于是将前面的函数改成
function isDisabled(element) { return element.matches(':disabled'); }进一步的,我检查了其它几个属性,包括
readonly,required,发现<fieldset>只支持disabled。 -

记一个正则问题
前几天写代码,遇到一个需求:
- 解析
sleep NUMBER这样的命令 - 能够识别缺参数或者参数错误的情况
这个正则并不复杂,初步写出来大概是这样:
sleep\s+(.*)。这样,$1 就是参数,然后就可以检验。但是.*匹配“任意字符出现零次或多次”,所以实际测试发现它根本不匹配任何参数。然后我就改成了
sleep(?:\s+(.*))?,然后在下一步 trim。这样,sleep后面整个都是可选参数,就能解决上面的问题。然后就被老板骂了……老板的答案是
sleep\s+(.*?)\s*$。重点在于后面的$,要求正则必须匹配行尾,这样一来,懒惰模式的.*?就需要一直匹配到行尾,并且尽量少匹配内容,所以诸如a b之类的情况也可以正常跑匹配了。
从这里,我学到:
$和\b虽然并不能匹配到一个确定的字符,但它们同样意义重大- 不特定长度匹配,包括
*,+,甚至{n, m},在懒惰模式下,后面都要尽量跟上明确的结束条件,以便让前面尽快结束。
- 解析
-

Puppeteer 笔记
记录使用 Puppeteer 的一些经验。
安装使用
puppeteer 是一个“库”,没有自带的命令行功能。所以要使用的话必须写一个文件,然后实现对应的功能。
npm i puppeteer在墙内安装
puppeteer 里面包含完成的浏览器程序,少说也是 100MB,所以需要下载比较长的时间,在墙内则经常会失败。所以建议国内开发者用淘宝的源:
npm config set puppeteer_download_host=https://npm.taobao.org/mirrorsCould not find browser revision xxxxx如果安装依赖时,默认的浏览器下载不成功,使用时可能会报这个错误。里面的
xxxxx是某个版本号。此时可以使用npm i puppeteer --force重新安装。如果是墙内用户,那么按照上一小节设置源之后再安装,多半就可以解决问题了。在 WSL 下使用
关于 WSL 使用,请参考这篇博文:在 Windows 10 WSL 中使用 Puppeteer
我的测试仓库和工具


