分类
nodejs

Node.js 里使用 Promise 的小技巧

Node.js 8 的时候,引入了 util.promisify() 方法,可以把 node-like 的回调函数改造成返回 Promise 实例的方法,我当时还写了篇博文《Node.js 8 中的 util.promisify》小记。

所以我现在写 Node.js 基本都是这种风格:

const fs = require('fs');
const {promisify} = require('util');

const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);

刚才在推上看到两位大佬聊起这个话题,发现可以这么搞:

去查了一下 Node.js 的文档,发现这是 v10 新增的 API,升级之后即可使用。

我比较喜欢这么做:

const {promises: {readFile, writeFile}} = require('fs');

(async () => {
  let content = await readFile('1.txt', 'utf8');
  content = doSthToContent(content);
  await writeFile('2.txt', content, 'utf8');
  console.log('ok');
})();
分类
js 技术

最近折腾 @babel/preset-env 的一些小心得

近来厂里的项目越来越多,代码共享必不可少。我现在采取的方案是:

  1. 把公共组件拿出来,开一个新仓库
  2. 使用 webpack 进行打包编译,libraryTarget: 'umd'
  3. 将打包编译的代码一起提交到仓库
  4. 使用 npm i <owner>/<repo> -S 安装依赖,因为我厂的仓库均为私有,所以不能发布到 NPM

这套方案简单好用,实操效果良好。接下来我希望优化打包结果,于是研究了打包配置项,下面是我的一点心得。

分类
vue

Chat:Vue 进阶必经之路

Vue 进阶必经之路

Vue 的学习曲线平缓,入门很简单,所以后发夺人,争取到一大批支持者,我也是其中之一。但是因为隐蔽了很多细节,所以我也没少踩坑,挠头拍桌,不厌其烦。如今,我终于突破屏障,遇到大部分问题,都能举一反三,快速定位、快速解决。这段过程,难免追本溯源,穷究细节。我希望通过这次分享,把我的经验和收获传达给大家。

面向听众:

1. 有一定 Vue 开发经验,希望进一步提升;
2. 平时业务代码写得多,想学习技术细节。

写完了,不得不说,没有预先想象中写得好。原因嘛,当然是工作太忙,能够写文的时间不太够。以后还是平时多写,Chat 当汇总比较好。

不过还是希望大家都来看,毕竟我这两年踩坑得到的 Vue 经验都在里面了。

分类
js

用 `resize` 和 MutationObserver 实现缩放 DOM 并记录尺寸

我厂既然号称“机器编程”,DSL 便属于基础配置。于是,各个产品几乎都需要用到 CodeMirror,用于在线写代码。大家的屏幕分辨率不同,对编辑器的大小要求也不同,最简单的办法就是让大家自己调整,并且将尺寸保存在本地。

以前的做法会复杂一些:

  1. 拿一个元素作为 handle 放在角落里
  2. mousedown 时开始侦听 mousemove,动态调整文本框大小
  3. mouseup 时保存尺寸

如今大家应该都有注意到,<textarea> 右下角多了一个缩放用的 handle。这个功能自然不是 <textarea> 独享,而是受 CSS 样式 resize 控制,任何块级元素都适用。MDN 文档在此,建议大家先好好看一遍。

分类
js

CodeMirror 笔记

这篇文章用来记录使用 CodeMirror 时的一些心得。

分类
js 技术

使用 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 还有其它方法也很有用,尤其是 get 对应的 set ,以后再介绍。大家可以自己抽空研究下。

参考

  • 阮一峰的 ES6
  • 《深入理解 ES6》

分类
vue

Chat idea:Vue 进阶之路

本文记录一下 Vue 里常见的坑,为下一次 GitChat 做准备。

分类
js

WebSocket.onerror 没有错误描述

用 WebSocket 时遇到一个问题:有时候连接出错,我希望把错误描述报告给用户,方便他们排除。但是尝试了好几种方法,都无法获得错误描述。

于是只有 Google 之,发现了这个答案:https://stackoverflow.com/questions/18803971/websocket-onerror-how-to-read-error-description。原来是为了防止开发者利用 WebSocket 搞破坏,扫描特定条件下的网络,WebSocket 的 ErrorEvent 只包含一个 error,没有更进一步的描述。oncloseCloseEvent.code也只有 1006——非正常退出,这样毫无价值的信息。 

所以我的处理方式是:建议用户按 F12 打开开发者工具看错误信息。

分类
js

在 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 以二进制文档流的方式来处理返回的数据。 

分类
nodejs

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,背景知识介绍结束。近期开发中,我需要执行一个命令,并且取得它的 stdoutstderrexit 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,静电容,试用一下,效果还不错。略硬,段落感不强,声音不大。