All Posts

[译] Node.js 流: 你需要知道的一切

图片来源 Node.js 中的流有着难以使用,更难以理解的名声。现在我有一个好消息告诉你:事情已经不再是这样了。 很长时间以来,开发人员创造了许许多多的软件包为的就是可以更简单的使用流。但是在本文中,我会把重点放在原生的 Node.js 流 API上。 “流是 Node 中最棒的,同时也是最被误解的想法。” — Dominic Tarr 流到底是什么呢? 流是数据的集合 —— 就像数组或字符串一样。区别在于流中的数据可能不会立刻就全部可用,并且你无需一次性的把这些数据全部放入内存。这使得流在操作大量数据或是数据从外部来源逐段发送过来的时候变得非常有用。 然而,流的作用并不仅限于操作大量数据。它还带给我们组合代码的能力。就像我们可以通过管道连接几个简单的 Linux 命令以组合出强大的功能一样,我们可以利用流在 Node 中做同样的事。 Linux 命令的组合性 const grep = ... // 一个 grep 命令输出的 stream const wc = ... // 一个 wc 命令输入的 stream grep.pipe(wc) Node 中许多内建的模块都实现了流接口: 截屏来自于我的 Pluralsight 课程 —— 高级 Node.js 上边的列表中有一些 Node.js 原生的对象,这些对象也是可以读写的流。这些对象中的一部分是既可读、又可写的流,例如 TCP sockets,zlib 以及 crypto。 需要注意的是这些对象是紧密关联的。虽然一个 HTTP 响应在客户端是一个可读流,但在服务器端它却是一个可写流。这是因为在 HTTP 的情况中,我们基本上是从一个对象(http.IncomingMessage)读取数据,向另一个对象写入数据(http.ServerResponse)。 还需要注意的是 stdio 流(stdin,stdout,stderr)在子进程中有着与父进程中相反的类型。这使得在子进程中从父进程的 stdio 流中读取或写入数据变得非常简单。

正则表达式中的悲观回溯

前几天有小伙伴来求救说页面上有一个 input 框,随着用户不断输入内容,页面响应会越来越慢直到完全失去响应。 简单沟通过后得知具体场景是这样的: input 框中允许用户输入一连串逗号分隔的商品id 在用户输入的过程中实时检测用户输入的内容是否符合规则,若不符合则给出提示信息 小伙伴的解决方案也很直接: 给 input 框绑定 keyup 事件。 在 keyup 事件回调函数中通过正则表达式判断是否符合规则,决定是否展示提示信息。 经过反复验证得到如下规律: 用户在输入商品 id 的过程中(连续输入多个数字)不会卡顿 当用户输入逗号时,出现卡顿。随着输入商品 id 的数量增加,卡顿越来越明显,直至浏览器失去响应。 于是打开 Chrome 开发者工具,选择 Performance (原 Timeline) 标签页。将整个过程记录下来,得到如下时间线: 其中黄色宽条表示 JavaScript 主线程的执行情况。连续的黄条越长,表示单次 JavaScript 运行的时间越长。也就意味着 UI 失去响应的时间越长。这一点从截图中的蓝色框中也可以得到印证。蓝色框中的红色长条表示浏览器一帧(一次渲染)所需要的时间。 那么到底是 JavaScript 中的哪些代码占中了这么长 CPU 时间呢?我们在底部的选项卡中选中 Bottom-Up ,按 Total Time 降序排列。得到如下结果: 可以看出,72.% 的 CPU 时间用在了一条正则表达式上。你肯定想到了,这就是小伙伴用来检查用户输入是否合法的正则表达式。 完整的正则表达式是这样的: /^\s*((\d+(\,|,)\d+)*|(\d+))\s*$/ 接着去 regex101 上测试一下,测试数据如下,由 10 个商品 ID 组成的字符串: 123456789,123456789,123456789,123456789,123456789,123456789,123456789,123456789,123456789,123456789 执行结果如下:

[译] 为何TypeScript愈发流行了?

在掘金翻译计划里翻译的一篇文章。感觉对自己挺有启发的。分享给大家。 原文地址:Why TypeScript Is Growing More Popular 原文作者:Mary Branscombe 校对者:Aladdin-ADD Germxu 为何 TypeScript 这么流行呢?许多主流的开发框架依赖于它,它还能提高开发者在不断变化的 JavaScript 世界中的生产力。 在最近的 Stack Overflow 开发者调查以及年度 RedMonk 编程语言排名中都显示 TypeScript —— 由微软发起的结合了编译高级 JavaScript 特性与静态类型检查及工具的开源项目 —— 正在达到新的人气高度。通过为 JavaScript 提供最基本的检查语法,TypeScript 允许开发者对他们的代码进行类型检查,这可以暴露 bug 并改善大型 JavaScript 代码库的结构和文档。 参与了 Stack Overflow 调查的开发者中有 9.5% 的人正在使用 TypeScript,这使得 TypeScript 成为了第九流行的编程语言,排名在 Ruby 之前,用户量是 Perl 的两倍。此次 Stack Overflow 调查中的受访者来自不同领域,使用最广泛的两种语言是 JavaScript 和 SQL,这说明此次调查并非只针对前端开发。事实上,TypeScript 程序员出现在了参与 Stack Overflow 调查的所有 4 种工作角色中:web 开发者、桌面开发者、系统管理员与 DevOps 以及数据科学家。 RedMonk 的排名将 Stack Overflow 的数据与 GitHub 上的 pull request 结合起来试图理解开发者的想法以及他们正在使用什么。TypeScript 同样受到了开发者的欢迎,排名从第 26 位上升到了第 17 位。其中一部分原因是 TypeScript 在 Stack Overflow 上关注度的提升,但主要还是因为在 GitHub 上参与的开发者在不断增多。

[译] 我是如何成为一名更优秀的程序员的

原文地址:http://jlongster.com/How-I-Became-Better-Programmer 译者注:本文作者 James Long,前 Mozilla 工程师,NodeJS, ReactJS 社区活跃开发者。NodeJS 著名模板引擎 Nunjucks 作者,JavaScript 格式化工具 Prettier 作者。在 Mozilla 工作 6 年后离开,年仅 32 岁自己创业开公司。其人生经历值得大部分程序员学习。 在React Conf上有几位朋友咨询我如何成为一名更优秀的程序员。由于某种原因,人们认为我是一个值得倾听的高级程序员。所以我想有必要把我这些年编程路上的『心路历程』写下来。 关于我的一些详细信息:我现年32岁,有10年以上扎实的工作经验。直到最近几年我才对自己所做的工作充满信心。即使是现在,我也在不断质疑自己。问题在于,这种质疑并不会消失,所以你要做的就是无视它,不断的解决问题,不断的积累经验。 首先我要说明的是以下提到的只是一些帮你提升技能的小贴士。最终你还是需要找到一条最适合你自己的路。这些只是我发现对我有帮助的点。

[译] 6个Async/Await完胜Promise的原因

原文地址:https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9 友情提醒:NodeJS自从7.6版开始已经内置了对async/await的支持。如果你还没用过该特性,那么接下来我会给出一系列的原因解释为何你应该立即开始使用它并且会结合示例代码说明。 async/await快速入门 为了让还没听说过这个特性的小伙伴们有一个大致了解,以下是一些关于该特性的简要介绍: async/await是一种编写异步代码的新方法。在这之前编写异步代码使用的是回调函数和promise。 async/await实际是建立在promise之上的。因此你不能把它和回调函数搭配使用。 async/await和promise一样,是非阻塞的。 async/await可以使异步代码在形式上更接近于同步代码。这就是它最大的价值。 语法 假设有一个getJSON方法,它返回一个promise,该promise会被resolve为一个JSON对象。我们想要调用该方法,输出得到的JSON对象,最后返回"done"。 以下是使用promise的实现方式: const makeRequest = () => getJSON() .then(data => { console.log(data) return "done" }) makeRequest() 使用async/await则是这样的: const makeRequest = async () => { console.log(await getJSON()) return "done" } makeRequest() 使用async/await时有以下几个区别: 在定义函数时我们使用了async关键字。await关键字只能在使用async定义的函数的内部使用。所有async函数都会返回一个promise,该promise最终resolve的值就是你在函数中return的内容。 由于第一点中的原因,你不能在顶级作用域中await一个函数。因为顶级作用域不是一个async方法。 // this will not work in top level // await makeRequest() // this will work makeRequest().then((result) => { // do something }) await getJSON()意味着直到getJSON()返回的promise在resolve之后,console.

Webpack2中的NamedModulesPlugin与HashedModuleIdsPlugin

要讨论Webpack 2中新增的这两个plugin的功能,还要先从使用Webpack打包的项目的前端资源缓存方案说起。 通常在使用了Webpack的项目中我们会使用CommonsChunkPlugin来将所有依赖的第三方包打包到一个名为vender的chunk中。与此同时,为了避免每次更改项目代码时导致vender chunk的chunkHash改变,我们还会单独生成一个manifest chunk。 举个例子,假设我们有一个项目,项目中入口文件为index.js。其内容如下: import add from './src/add'; import leftPad from 'left-pad'; import jsonp from 'jsonp'; add(1, 2); 通常我们的webpack.config.js文件就会有类似如下的配置: const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { 'app': './index.js', 'vender': ['left-pad', 'jsonp'] }, output: { filename: '[name].[chunkHash].js', path: path.resolve(__dirname, 'build') }, resolve: { extensions: ['.js'] }, module: { ... }, plugins:[ new webpack.optimize.CommonsChunkPlugin({ name: ['vender', 'manifest'], minChunks: Infinity, }) ] }; 这时,通过Webpack打包,会生成三个文件: 假设我们修改了./src/add.js文件,重新打包,会得到:

在JavaScript项目中锁定npm依赖包版本

问题 最近在项目中遇到这样一个问题,webpack生成的vender包的哈希值在我和同事的电脑上不一致。由于之前已经配置过了CommonsChunkPlugin(配置如下),所以我们期望的结果是在不同环境下构建出的文件哈希值应该是一致的。 注:只给出了和本文内容相关的配置项 module.exports = { entry: { app: './src/js/app.jsx', vender: [ 'classnames', 'react', 'react-dom', 'redux', 'react-redux', 'redux-promise-middleware', 'updeep', 'axios', 'jdc-rc-list', 'react-router', 'react-router-redux' ] }, output: { path: path.resolve(__dirname, './build/js/'), filename: (isDevelopmentEnvironment ? '[name].bundle.js' : '[name].[chunkhash].js'), chunkFilename: (isDevelopmentEnvironment ? '[name].bundle.js' : '[name].[chunkhash].js') }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['vender', 'manifest'], minChunks: Infinity, }) ] }; 调查 经过多次验证发现,我们在各自的电脑上多次构建出来的哈希值可以保持一致,只是在两台电脑上不一致。考虑到vender中打包的都是第三方依赖,于是猜测是两台电脑上安装的依赖包不同。接着对比了两人的package.json中的dependencies,完全一致。 考虑到package.json文件中包版本中的^符号匹配的范围比较大。参考npm官方给出的解释: ^1.2.3 := >=1.2.3 <2.0.0 ^0.2.3 := >=0.2.3 <0.3.0 ^0.0.3 := >=0.0.3 <0.

React Conf 2017视频 百度网盘地址

React Conf 2017的全部视频已经在YouTube上放出来了。为了方便在家里的电视上播放,就全部下载了一套。顺便上传了百度网盘一份。感兴趣的可以看看哦。全部720p。 下载地址: http://pan.baidu.com/s/1gfl5FzX

园博园一日游

来北京快3年了,之前每次坐高铁回家都会路过园博园。每次透过车窗看到园里漂亮的风景,总会和老婆商量着什么时候来。可惜我住在大东边,园博园在帝都西南角,每次想到坐地铁要2个多小时就放弃了。现在有车了,出行方便了,却又总也想不起来了。昨天还是老婆提议:『我们明天去园博园啊?!』于是俩人一拍即合,来一场说走就走的春游。 订票 确定要去,马上在携程上定了两张门票。原价20,携程上18。(点此订票)注意:携程上买的电子票只能在园区三号门的售票处换票。这点千万注意。 出发 今天早起看天气,格外给力。天很蓝,云很白。吃过早饭,8:40从家出发。一路畅通,只用1个小时就把五环跑了半圈,到达目的地。 到达导航终点遇到了第一个问题,百度地图上搜到位于长顺一路上的停车场都是临时停车场,现在已经关闭了。于是掉头往园区正门开去,一路上有不少车在掉头。看来是不少人都中招了。不过好消息是园区正门有保安在指挥,正门再往西一点点就是正式停车场了。 蓝色圈圈就是停车场的位置。 停好车,背上包往园区正门走。换票很方便,把携程发来的取票码出示给工作人员就好了,购买特价票(包括电子票)必须要出示相关证件哦。排在我前面的一个大姐买了老人票但是没带证件,只好退票重新买。另外一个要注意的就是,园区不允许携带宠物进入。 入园 正门门口 入园后,园区内部是由许多馆/园组成的。比如一进门看到的鄂尔多斯馆、合肥园、荆门园等等。都是以省市或古地名命名的。或大或小,各有特色。随便放几张照片感受下: 晋中园 晋中园内的戏台 合肥园门口的牌楼 粤秀 各种园实在太多,我们自己走的也只是很小一部分,就不一一列举了。有兴趣还是亲自去看一看。下面说三个重点推荐的景观吧。 附一个园区地图(可以右键新窗口打开查看大图) 北京园 北京园应该是园博园里最大的一个园了,毕竟是首都嘛。建筑风格也保持了皇家建筑的大气,威严。 北京园内的主要建筑:聚景阁 古都北京山川形胜写意 忆江南 这里可以说是今天行程最大的收获了。出乎意外的美。置身其中,仿佛一下子去到了江南某个小城的私家园里之中。 永定塔 永定塔位于园内西北部的半山腰上,是园区的最高点,也是我今天走到的最远的位置。老婆在逛完忆江南后就走不动了,找了个长凳休息。于是我开启了暴走模式,直奔永定塔。 终于来到山下,拾阶而上,一路没什么人。 离塔越来越近 途径文源亭 文源亭后是两条铁道,时不时还会有货运列车经过。 在文源亭远眺北京城,可以看到中央电视塔,国贸。这天气,视野真的很不错。 继续上山,偶然发现的隧道。从文字上也看的出很有历史啦。前面提到的两条铁轨就穿过这里从永定塔下穿行而过。 终于来到塔下,可惜并不对外开放。只能在外边看看啦。 餐饮 从永定塔下来已经是下午1点了,还没吃午饭。于是一边往大门走一边找吃的。然而并没有什么收获,要么是路边小亭子里吃泡面,要么是去少数几个餐厅里吃。看到一个吉祥馄炖,走进去看了看就出来了。环境很一般,很多人在打扑克牌,比较吵。上一个菜价单供参考: 最后午饭在石景山华联的呷哺呷哺解决的。从园博园开车过去大约20分钟左右。可选择的的餐馆也很多。比园区里的那些餐饮靠谱多了。 费用小计 最后附一个今天的费用小计,供参考: 园博园停车:20(5元/小时) 园博园门票:36(18元/人) 华联停车:6元 呷哺呷哺:74元

配置Fiddler拦截iOS/Andorid的https请求

Fiddler可以配置用来拦截https请求。但默认配置下仅支持拦截PC上的请求。在移动端上的https请求会因为证书问题而失败。如下图所示: 要解决这个问题,只需要在iOS/Android系统上安装一个安全证书即可。具体步骤如下: 访问http://www.telerik.com/fiddler/add-ons,下载并安装CertMaker for iOS and Android插件。 安装完成后重启Fiddler。 重启后浏览器访问http://ipv4.fiddler:8888,如果看到如下内容,表示安装成功。 在手机浏览器(iOS建议Safari)里打开前边提到的链接,点击页面中最后一个链接FiddlerRoot certificate。下载完后会提示如下页面: 点击安装,弹出安全认证,要求输入密码。输入后出现以下页面: 继续点击安装。安装成功提示如下: 到这里,所有的配置工作就全部做完了。现在再次访问https页面,已经可以正常打开了。