Skip to content

Instantly share code, notes, and snippets.

@qiulang
Last active April 30, 2019 08:00
Show Gist options
  • Save qiulang/57ff3b505752fa46433001d7aaeb8d1b to your computer and use it in GitHub Desktop.
Save qiulang/57ff3b505752fa46433001d7aaeb8d1b to your computer and use it in GitHub Desktop.
从nodejs 6 到 8, from callback hell to promise chain to async/await

过去一年里我把node 6升级到 8 (开发环境下甚至鼓励大家用最新的node 10),一个主要目的就是为了解决callback hell的问题.

回调地狱的问题我不是第一次碰到,在做iOS开发时候,使用AFN就有这个“Pyramid of doom”的问题,当时的解决办法,也是后来用swift要求大家尽量用guard,说白了就是early return 但这个方法对nodejs的回调地狱不适用(用命名函数可以部分解决)

刚开始接触node,对promise还不熟悉,为了解决callback hell 首先引入的是 async这个模块 但是用async总感觉不是很自然, boilerplate code也不少。另,没有用其他的库,比如thenjs原因很简单:<1> 它的star数量和async不能比,这是我选开源库一个最重要参考 <2>知道以后肯定会用promise,不想再引入一个“似是而非”的then

promise chain是在熟悉了node之后很自然会引入的第二个解决方案,关于promise chain这篇文章 We have a problem with promises 一定要读透。

MDN对promise的讲解也很到位、全面。如果还觉得不够,那就看看javascript.info的几篇文章promise async/await, rethrow

要点其实也简单,每个then里一定记得要return, 如果直接return值,这个值会被包裹成promise.resolve的值

我自己理解这些概念还是花了点时间,在SO提了一个问题,得到很好解答

要写好promise chain并不是一件容易的事,debug也是个大问题,因为没法对then设置断点。 所以当知道node 8已经很好支持async/await后我决定把一些原来用 promise chain写的代码改为 async/await,一方面熟悉async/await为以后开发做准备;一方面也是为了review下原先没机会review的代码。

其实我们有些模块已经是用 co 但因为知道TJ大神退出node好多年 co库三年多都不更新,所以也借着这个机会一并全都换了

使用async/await本身很简单(这也是必然的,因为它的出发点就是让异步代码像同步代码),只是有几点要注意:

  1. 不需要串行执行的代码就用 Promise.all
  2. 如果某一步出错了,如何退出? 特意在SO提了这个问题await Promise.reject or throw error to bail out? 我比较倾向 throw
  3. 原来用 async module代码在引入async/await要怎么改? 还好async也支持 async/await, 把原来callback直接改成return就是

Async accepts async functions wherever we accept a Node-style callback function. However, we do not pass them a callback, and instead use the return value and handle any promise rejections or errors thrown.

  1. async/await 性能问题、bluebird还要吗,可不可以就用node的知道promise. 这个问题应该是真的碰到性能瓶颈才需要花时间去调研的问题。但实现知道一些大致要点也不错。这里有一份简单比较,总的来说bluebird依旧需要

后记,如何升级node版本

node版本管理工具就两个 nvm 和 n,详细的使用上的区别可以看这篇 简单的说,nvm真的是比较麻烦。

对我们来说不需要频繁切换版本,就是要升级下一个LTS版本,而且比起nvm的安装, 执行sudo npm install -g n 简单多了,所以自然是选用n.

在Ubuntu上,通过下载Linux Binaries 升级并不是好办法 ,如果已经有了一个老版本的node,选用n是最方便的办法 ('The irony is not lost on me that you must first install node in order to install the node manager.')。

另,在Ubuntu上 全新的安装可以参见这里

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment