正式使用node.js作为开发语言已经两个月了, 从一开始的别扭地使用到现在的越发得心应手, 写篇博客记录一下 这两个月来的心路历程。

用node.js做了什么

项目采用前后端分离的方式开发。

前端由vuejs构建, 后端的web服务器则是由node.js的express框架进行构建,双方通过restful风格的http接口通信。

而我主要负责后端的部分。 简单地说,就是写后端的CURD接口。

全都是异步?

如果一个编程语言所有接口都是异步的, 那么会怎么样? 呃, 会变成node.js这样。

nodejs和浏览器js的引擎一样。都是基于事件流的循环执行回调函数。

JavaScript引擎采用回调的形式来处理异步问题。当进行可能产生阻塞的IO操作时(比如网络请求、文件读写),那么交给底层的线程来处理, 同时JavaScript引擎内部维护一个执行队列,轮询底层线程的执行结果,当某个执行完成时,调用对应的回调函数返回结果。

Node.js和Java在线程最大的区别应该是。Node.js的子线程是底层控制的,对于开发者而言是不可见的(Node.js 10 以后的版本添加了实验性功能,支持多线程处理CPU密集型问题。),好处就是开发者不再需要关注线程的管理,只需要写好异步代码就行,而Java提供了多线程的API,需要开发者手动管理。

如果所有函数都是异步, 那么代码应该怎么写呢? 例如一个同步的python代码块是这么写的:

1
2
3
num1 = get_data1()
num2 = get_data2()
num3 = num2- num1

那么node.js块则应该是这样:

1
2
3
4
5
get_data1(function(err, num1){
    get_data2(function(err, num2){
        var num3 = num2- num1
    })
})

没错, js用回调函数的方式去获取异步函数的结果, 细心的朋友可能已经发现了, 回调函数就是俄罗斯套娃, 一层套一层, 两三层还好, 再多几层简直会让人产生生理不适。

无穷无尽的回调地狱

在我接手项目之后,发现项目里面大部分是这样一层叠着一层的函数, 最多的可以叠到十几个函数, 硬着头皮改了两个星期, 对我一个 之前写python的人来说,简直像吃了两个星期的屎。 然而有一天在浏览ES6的语法时, 发现了一个新的语法, 避免了我继续进行这 饕餮的盛宴。

async,await拯救node.js

说async之前必须先说一下Promise.

所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事情(通常是一个异步操作)。从语法上说,Promise是一个对象,从他可以获取异步操作的消息。

Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

async/await其实是 Promise 的语法糖,它能实现的效果都能用 then 链来实现,它是为优化 then 链而开发出来的。async 声明 function 是异步的,await等待某个操作完成。语法上强制规定 await 只能出现在 asnyc 函数中。

async 函数返回的是一个 Promise 对象。 await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。

上面的代码用async, await写就是这样:

1
2
3
var num1 = await get_data1()
var num2 = await  get_data2()
var num3 = num2- num1

可以看到已经和python的语法非常像了, 开发效率提升300%

生态环境

node.js的第三方库也是非常繁荣的。 特别是涉及到web操作的一些库, 足以和python媲美。 有一句话叫做, 如果一个程序能被 javascript写, 那么它就一定会被javascript写一遍。 熟悉node.js之后, 转前端也更容易了呢。。。