All Posts

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

原文地址: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打包,会生成三个文件:

在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.

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页面,已经可以正常打开了。

键盘鼠标共享神器 Mouse without Borders

如果你像我一样办公桌上有2台或以上的电脑(比如一个台式机,一个笔记本),那么有个问题一定在困扰着你。那就是两台电脑有各自的一套键鼠设备。来回切换使用两台电脑的时候要在两套键鼠设备之前切换,非常不方便。同时,两套设备还会占据办工作上很大的空间。 今天要分享一个神器帮你解决这个问题,那就是微软出品的Mouse without Borders。通过它,你可以利用一套键鼠设备在若干台(最多4台)电脑之前无缝切换。就好像是在两个连接在同一个电脑的两个显示器之间切换一样方便。 使用方法 下载并安装Mouse without Borders,需要连接的两台电脑上都要安装。 下载地址 在两台电脑上都启动程序。会看到如下的欢迎界面 在第一台电脑上点击NO,看到如下页面。记下这里的SECURITY CODE。 在第二台电脑上点击YES,输入之前记下的SECURITY CODE和主机名。点击LINK。 连接成功后会出现以下提示界面: 按需修改配置。配置界面如下。通常默认配置已经够用了。如果确有需要按需调整即可。 功能,特色 Mouse without Borders的主要特色有: 一套键鼠控制多台设备 各台设备间完全平等,可以使用任意一台主机的键鼠控制任意其他主机 各台主机间共享剪切板内的内容,随意复制粘贴(支持复制文件) 支持在主机间拖拽复制文件 可以截取任意一台设备上屏幕的内容(Ctrl+Shift+S进入截屏模式,鼠标拖拽选择截屏区域,在本地打开画图工具,Ctrl+V即可看到截图内容) 缺点 我的能想到的唯一缺点就是不支持跨平台,仅支持Windows操作系统。毕竟是Microsoft出品。。。 类似产品 Synergy 功能与Mouse without Borders类似。主要区别在于,与Mouse without Borders相比: 优点: 跨平台 支持Windows Linux Mac 缺点: 有服务器,客户端的概念。只能使用服务器的键鼠控制其他主机 不支持在主机间复制粘贴文件或拖拽复制文件(官方宣传支持该功能,但始终复制不成功) 不支持截取其它主机的屏幕 综上,如果你需要跨平台,那么没得选,只能Synergy。否则果断选择Mouse without Borders。

Redux 3.6.0 源码阅读 之 src/createStore.js

嗯,就是学习一下,读读源码。顺便把源码里的文档翻译了一下并添加了一些简单的注释。 本文对应的文件是src/createStore.js import isPlainObject from 'lodash/isPlainObject' import $$observable from 'symbol-observable' /** * ActionTypes里定义的是Redux保留的私有action。 * 对于任何未知的action,你必须返回store的当前状态。 * 如果传入的当前状态是undefined,你必须返回store的初始状态。 * 不要在应用代码中直接引用这些action。 */ export var ActionTypes = { INIT: '@@redux/INIT' } /** * createStore方法用于创建一个保存程序状态的store。 * 改变store中数据的唯一方法是调用store的`dispatch()`方法。 * * 你的应用中应该只有一个store。为了将程序状态中不同部分的变更逻辑 * 组合在一起,你可以通过`combineReducers`方法将多个reducer组合成一个reducer。 * * @param {Function} reducer 一个返回应用下一状态的函数,入参是程序的当前状态以及 * 要发送的action。 * * @param {any} [preloadedState] store的初始状态。你可以选择性的为store指定一个 * 初始状态。 * 如果你使用了`combineReducers`方法来生成最终的reducer。那么这个初始状态对象的 * 结构必须与调用`combineReducers`方法时传入的参数的结构保持对应关系。 * * @param {Function} enhancer store增强器。你可以选择性的传入一个增强函数来扩展 * store的功能,例如中间件,时间旅行,持久化等。Redux自带的唯一一个增强器是 * `applyMiddleware()`方法。 * * @returns {Store} 返回一个可以读取状态,发送action以及订阅变更通知的Redux store。 */ export default function createStore(reducer, preloadedState, enhancer) { // 如果只传入reducer和enhancer,则store的初始状态为undefined if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } // enhancer必须是一个函数 if (typeof enhancer !

[译]什么是Promise.try

原文地址 http://cryto.net/~joepie91/blog/2016/05/11/what-is-promise-try-and-why-does-it-matter/ 在#Node.js#频道里经常困扰大家的一个话题是Bluebird提供的Promise.try方法。大家并不清楚该方法的功能也不知道为何要使用它。同时,几乎所有的关于Promsie的指南中针对该方法错误的演示使得这种情况没有任何改善。 在本文中,我会尝试解释究竟什么是Promise.try以及为何你应该使用它。我假设你已经对Promise有所了解并且知道.then在Promise中的作用。 即使你在使用一个不同的Promsie实现(例如ES6 Promise),本文还是可以帮到你。文章末尾我会解释如何在非Bluebird环境中实现相同的功能。 究竟什么是Promise.try呢? 简单来说,除了不需要跟在一个前置Promise之后以外,Promise.try很像.then。这么说还是有一些含糊不清,所以让我们先看一个示例。 以下是一段典型的Promise使用场景: function getUsername(userId) { return database.users.get({id: userId}) .then(function(user) { return user.name; }); } 到目前为止,一切顺利。我们假设database.users.get会返回一个Promise,并且该Promise最终会返回一个带有name属性的对象。 以下是同样的代码,但是引入了Promise.try: var Promise = require("bluebird"); function getUsername(userId) { return Promise.try(function() { return database.users.get({id: userID}); }).then(function(user) { return user.name; }); } 可以看到,我们的调用链以Promise.try而不是database.users.get开始。像使用.then一样,我们执行Promise.try方法并传递给它一个直接返回database.users.get调用的函数。 这样做有什么意义呢? 以上的代码看起来似乎是多余的。但实际上它有以下几个优点: 更好的错误处理 同步代码中的异常不论出现在何处都会以rejection的形式向Promise链后端传递。 更好的兼容性 你可以始终使用你自己喜欢的Promise实现,而不用担心第三方代码在使用哪个。 更好的代码阅读体验 所有的代码在水平方向上将处于同一个缩进层级,这将使你阅读代码变得更容易。 接下来我会逐一介绍这些优点: 1. 更好的错误处理 Promise的一个被大力宣扬的优点就是用户可以用同一种方式同时处理同步异常和异步异常 —— 同步异常会被捕获并且会作为一个rejected Promise向后传递。但事实真的是这样吗?让我们看看以下这个上文示例的小变种: function getUsername(userId) { return database.users.get({id: userId}) .then(function(user) { return uesr.