欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【nodejs】入门必知

程序员文章站 2022-07-10 15:41:02
...

https://i5ting.github.io/How-to-learn-node-correctly/#1

 

1.3.2. 安装Node.js环境

3m安装法

  • nvm(node version manager)【需要使用npm安装,替代品是yrm(支持yarn)】
  • nrm(node registry manager)【需要使用npm安装,替代品是yrm(支持yarn)】
  • npm(node packages manager)【内置,替代品是n或nvs(对win也支持)】

1.3.2.1. nvm

node版本发布非常快,而且多版本共存可能性较大,推荐使用nvm来安装node

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash

$ echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.zshrc
$ echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.zshrc
$ source ~/.zshrc

$ nvm install 0.10
$ nvm install 4
$ nvm install 6
$ nvm install 8

1.3.2.2. nrm

https://registry.npmjs.com 是node官方的源(registry),服务器在国外,下载速度较慢,推荐安装nrm来切换源,国内的cnpm和taobao的源都非常快,当然,如果你想自建源也是支持的。

$ npm install --global nrm --registry=https://registry.npm.taobao.org
$ nrm use cnpm

1.3.2.3. npm

nrm切换完源之后,你安装npm模块的速度会更快。

$ npm install --global yarn

npm基本命令

名称 描述 简写
npm install xxx 安装xxx模块,但不记录到package.json里 npm i xxx
npm install --save xxx 安装xxx模块,并且记录到package.json里,字段对应的dependency,是产品环境必须依赖的模块 npm i -s xxx
npm install --save-dev xxx 安装xxx模块,并且记录到package.json里,字段对应的dev-dependency,是开发环境必须依赖的模块,比如测试类的(mocha、chai、sinon、zombie、supertest等)都在 npm i -D xxx
npm install --global xxx 全局安装xxx模块,但不记录到package.json里,如果模块里package.json有bin配置,会自动链接,作为cli命令 npm i -g xxx

1.3.3. 常用软件

  • 1)oh my zsh是我最习惯的shell,终端下非常好用

配合iterm2分屏 + spectacle全屏,几乎无敌

  • 2)brew是mac装软件非常好的方式,和apt-get、rpm等都非常类似

安装4个必备软件

  • brew install git 最流行的SCM源码版本控制软件
  • brew install wget 下载、扒站神器
  • brew install ack 搜索代码神器
  • brew install autojump 终端下多目录跳转神器

  • 3)vim

我虽然不算vim党,但也深爱着。janus是一个非常好用的vim集成开发环境。比如ctrl-p、nerdtree等插件都集成了,对我这种懒人足够了。

1.3.4. IDE和编辑器

关于Node.js的IDE和编辑器有很多选择,对比如下

名称 是否收费 断点调试 功能
Webstorm 收费 支持 是IDE,在代码提示、重构等方面功能非常强大,支持的各种语言、框架、模板也非常多,支持断点调试,好处是特别智能,缺点也是特别智能
Sublime/TextMate 收费 不支持 编辑器里非常好用的,textmate主要针对mac用户,sublime是跨平台的,相信很多前端开发都熟悉
Vim/Emacs 免费 不支持 命令行下的编辑器,非常强大,难度也稍大,但更为酷炫,而且对于服务器部署开发来说是值得一学的
VSCode/Atom 免费 支持 Atom比较早,功能强大,缺点稍卡顿,VSCode是微软出的,速度快,对于Node.js 调试,重构,代码提示等方面支持都非常好

Visual Studio Code是一个运行于 Mac、Windows和 Linux 之上的,针对于编写现代 Web 和云应用的跨平台源代码编辑器。它功能强大,便于调试,加上它本身也是基于 Node.js 模块 electron 构建的,尤其要推荐大家使用。

Visual Studio Code(以下简称vsc)

  • vsc是一个比较潮比较新的编辑器(跨平台Mac OS X、Windows和 Linux )
  • vsc功能和textmate、sublime、notepad++,ultraedit等比较,毫不逊色
  • vsc尤其是在nodejs(调试)和typescript、go上支持尤其好
  • vsc提供了自定义 Debugger Adapter 和 VSCode Debug Protocol 从而实现自己的调试器

值得一学,我推荐VSCode编辑器!

【重点:】更多调试方法,参见https://github.com/i5ting/node-debug-tutorial

1.3.5. Node.js应用场景

《Node.js in action》一书里说,Node.js 所针对的应用程序有一个专门的简称:DIRT。它表示数据密集型实时(data-intensive real-time)程序。因为 Node.js 自身在 I/O 上非常轻量,它善于将数据从一个管道混排或代理到另一个管道上,这能在处理大量请求时持有很多开放的连接,并且只占用一小部分内存。它的设计目标是保证响应能力,跟浏览器一样。

这话不假,但在今天来看,DIRT 还是范围小了。其实 DIRT 本质上说的 I/O 处理的都算,但随着大前端的发展,Node.js 已经不再只是 I/O 处理相关,而是更加的“Node”!

Node.js 使用场景主要分为4大类

【nodejs】入门必知

  • 1)跨平台:覆盖你能想到的面向用户的所有平台,传统的PC Web端,以及PC客户端 nw.js/electron 、移动端 cordova、HTML5、react-nativeweex,硬件 ruff.io 等
  • 2)Web应用开发:网站、Api、RPC服务等
  • 3)前端:三大框架 React \ Vue \ Angular 辅助开发,以及工程化演进过程(使用Gulp /Webpack 构建 Web 开发工具)
  • 4)工具:npm上各种工具模块,包括各种前端预编译、构建工具 Grunt / Gulp、脚手架,命令行工具,各种奇技淫巧等

下面列出具体的 Node.js 的使用场景,以模块维度划分

分类 描述 相关模块
网站 类似于 cnodejs.org 这样传统的网站 Express / Koa
Api 同时提供给移动端,PC,H5 等前端使用的 HTTP Api接口 Restify / HApi
Api代理 为前端提供的,主要对后端Api接口进行再处理,以便更多的适应前端开发 Express / Koa
IM即时聊天 实时应用,很多是基于 WebSocket协议的 Socket.io / sockjs
反向代理 提供类似于 nginx 反向代理功能,但对前端更友好 anyproxy / node-http-proxy / hiproxy
前端构建工具 辅助前端开发,尤其是各种预编译,构建相关的工具,能够极大的提高前端开发效率 Grunt / Gulp / Bower / Webpack / Fis3 / YKit
命令行工具 使用命令行是非常酷的方式,前端开发自定义了很多相关工具,无论是shell命令,node脚本,还是各种脚手架等,几乎每个公司\小组都会自己的命令行工具集 Cordova / Shell.js
操作系统 有实现,但估计不太会有人用 NodeOS
跨平台打包工具 使用 Web 开发技术开发PC客户端是目前最流行的方式,会有更多前端开发工具是采用这种方式的 PC端的electron、nw.js,比如钉钉PC客户端、微信小程序IDE、微信客户端,移动的Cordova,即老的Phonegap,还有更加有名的一站式开发框架Ionicframework
P2P 区块链开发、BT客户端 webtorrent / ipfs
编辑器 Atom 和 VSCode 都是基于 electron 模块的 electron
物联网与硬件 ruff.io和很多硬件都支持node sdk ruff

Node.js 应用场景非常丰富,比如 Node.js 可以开发操作系统,但一般我都不讲的,就算说了也没多大意义,难道大家真的会用吗?一般,我习惯将 Node.js 应用场景分为7个部分。

1)初衷,server端,不想成了前端开发的基础设施 2)命令行辅助工具,甚至可以是运维 3)移动端:cordova,pc端:nw.js和electron 4)组件化,构建,代理 5)架构,前后端分离、api proxy 6)性能优化、反爬虫与爬虫 7) 全栈最便捷之路

编号 场景 说明
1 反向代理 Node.js可以作为nginx这样的反向代理,虽然线上我们很少这样做,但它确确实实可以这样做。比如node-http-proxy和anyproxy等,其实使用Node.js做这种请求转发是非常简单的,在后面的http章节里,有单独的讲解。
2 爬虫 有大量的爬虫模块,比如node-crawler等,写起来比python要简单一些,尤其搭配jsdom(node版本的jQuery)类库的,对前端来说尤其友好
3 命令行工具 所有辅助开发,运维,提高效率等等可以用cli做的,使用node来开发都非常合适,是编写命令行工具最简单的方式,java8以后也参考了node的命令行实现
4 微服务与RPC node里有各种rpc支持,比如node编写的dnode,seneca,也有跨语言支持的grpc,足够应用了
5 微信公众号开发 相关sdk,框架非常多,是快速开发的利器
6 前端流行SSR && PWA SSR是服务器端渲染,PWA是渐进式Web应用,都是今年最火的技术。如果大家用过,一定对Node.js不陌生。比如React、Vuejs都是Node.js实现的ssr。至于pwa的service-worker也是Node.js实现的。那么为啥不用其他语言实现呢?不是其他语言不能实现,而是使用Node.js简单、方便、学习成本低,轻松获得高性能,如果用其他语言,我至少还得装环境

可以说目前大家能够看到的、用到的软件都有 Node.js 身影,当下最流行的软件写法也大都是基于 Node.js 的,比如 PC 客户端 luin/medis采用 electron 打包,写法采用 React + Redux。我自己一直的实践的【Node全栈】,也正是基于这种趋势而形成的。在未来,Node.js 的应用场景会更加的广泛,更多参见 sindresorhus/awesome-nodejs

1.3.6. Node核心:异步流程控制

Node.js是为异步而生的,它自己把复杂的事儿做了(高并发,低延时),交给用户的只是有点难用的Callback写法。也正是坦诚的将异步回调暴露出来,才有更好的流程控制方面的演进。也正是这些演进,让Node.js从DIRT(数据敏感实时应用)扩展到更多的应用场景,今天的Node.js已经不只是能写后端的JavaScript,已经涵盖了所有涉及到开发的各个方面,而Node全栈更是热门种的热门。

直面问题才能有更好的解决方式,Node.js的异步是整个学习Node.js过程中重中之重。

  • 1) 异步流程控制学习重点
  • 2)Api写法:Error-first Callback 和 EventEmitter
  • 3)中流砥柱:Promise
  • 4)终极解决方案:Async/Await

1.3.6.1. 1) 异步流程控制学习重点

我整理了一张图,更直观一些。从09年到现在,8年多的时间里,整个Node.js社区做了大量尝试,其中曲折足足够写一本书的了。大家先简单了解一下。

【nodejs】入门必知

  • 红色代表Promise,是使用最多的,无论async还是generator都可用
  • 蓝色是Generator,过度货
  • 绿色是Async函数,趋势

结论:Promise是必须会的,那你为什么不顺势而为呢?

推荐:使用Async函数 + Promise组合,如下图所示。

其实,一般使用是不需要掌握上图中的所有技术的。对于初学者来说,先够用,再去深究细节。所以,精简一下,只了解3个就足够足够用了。

【nodejs】入门必知

结论

  1. Node.js SDK里callback写法必须会的。
  2. Node.js学习重点: Async函数与Promise
    1. 中流砥柱:Promise
    2. 终极解决方案:Async/Await

所以下面我们会分个小部分进行讲解。

1.3.6.2. 2)Api写法:Error-first Callback 和 EventEmitter

a)Error-first Callback 定义错误优先的回调写法只需要注意2条规则即可:

  • 回调函数的第一个参数返回的error对象,如果error发生了,它会作为第一个err参数返回,如果没有,一般做法是返回null。
  • 回调函数的第二个参数返回的是任何成功响应的结果数据。如果结果正常,没有error发生,err会被设置为null,并在第二个参数就出返回成功结果数据。

下面让我们看一下调用函数示例,Node.js 文档里最常采用下面这样的回调方式:

function(err, res) {
  // process the error and result
}

这里的 callback 指的是带有2个参数的函数:"err"和 "res"。语义上讲,非空的“err”相当于程序异常;而空的“err”相当于可以正常返回结果“res”,无任何异常。

b)EventEmitter

事件模块是 Node.js 内置的对观察者模式“发布/订阅”(publish/subscribe)的实现,通过EventEmitter属性,提供了一个构造函数。该构造函数的实例具有 on 方法,可以用来监听指定事件,并触发回调函数。任意对象都可以发布指定事件,被 EventEmitter 实例的 on方法监听到。

在node 6之后,可以直接使用require('events')

var EventEmitter = require('events')
var util = require('util')

var MyEmitter = function () {

}

util.inherits(MyEmitter, EventEmitter)

const myEmitter = new MyEmitter();

myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
    // Prints: a b {}
});

myEmitter.emit('event', 'a', 'b');

和jquery、vue里的Event是非常类似的。而且前端自己也有EventEmitter。

c)如何更好的查Node.js文档

API是应用程序接口Application Programming Interface的简称。从Node.js异步原理,我们可以知道,核心在于 Node.js SDK 中API调用,然后交由EventLoop(Libuv)去执行,所以我们一定要熟悉Node.js的API操作。

Node.js的API都是异步的,同步的函数是奢求,要查API文档,在高并发场景下慎用。

笔者推荐使用 Dash 或 Zeal 查看离线文档,经常查看离线文档,对Api理解会深入很多,比IDE辅助要好,可以有效避免离开IDE就不会写代码的窘境。

【nodejs】入门必知

1.3.6.3. 3)中流砥柱:Promise

回调地狱

Node.js 因为采用了错误优先的回调风格写法,导致sdk里导出都是回调函数。如果组合调用的话,就会特别痛苦,经常会出现回调里嵌套回调的问题,大家都非常厌烦这种写法,称之为Callback Hell,即回调地狱。一个经典的例子来自著名的Promise模块q文档里。

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});

这里只是做4步,嵌套了4层回调,如果更多步骤呢?很多新手浅尝辄止,到这儿就望而却步,粉转黑。这明显不够成熟,最起码你要看看它的应对解决方案吧!

Node.js 约定所有Api都采用错误优先的回调方式,这部分场景都是大家直接调用接口,无太多变化。而Promise是对回调地狱的思考,或者说是改良方案。目前使用非常普遍,可以说是在async函数普及之前唯一一个通用性规范,甚至 Node.js 社区都在考虑 Promise 化,可见其影响之大。

Promise最早也是在commonjs社区提出来的,当时提出了很多规范。比较接受的是promise/A规范。后来人们在这个基础上,提出了promise/A+规范,也就是实际上现在的业内推行的规范。ES6 也是采用的这种规范。

Promise意味着[许愿|承诺]一个还没有完成的操作,但在未来会完成的。与Promise最主要的交互方法是通过将函数传入它的then方法从而获取得Promise最终的值或Promise最终最拒绝(reject)的原因。要点有三个:

  • 递归,每个异步操作返回的都是promise对象
  • 状态机:三种状态转换,只在promise对象内部可以控制,外部不能改变状态
  • 全局异常处理

1)定义

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

每个Promise定义都是一样的,在构造函数里传入一个匿名函数,参数是resolve和reject,分别代表成功和失败时候的处理。

2)调用

promise.then(function(text){
    console.log(text)// Stuff worked!
    return Promise.reject(new Error('我是故意的'))
}).catch(function(err){
    console.log(err)
})

它的主要交互方式是通过then函数,如果Promise成功执行resolve了,那么它就会将resolve的值传给最近的then函数,作为它的then函数的参数。如果出错reject,那就交给catch来捕获异常就好了。

Promise 的最大优势是标准化,各类异步工具库都按照统一规范实现,即使是async函数也可以无缝集成。所以用 Promise 封装 API 通用性强,用起来简单,学习成本低。在async函数普及之前,绝大部分应用都是采用Promise来做异步流程控制的,所以掌握Promise是Node.js学习过程中必须要掌握的重中之重。

Bluebird是 Node.js 世界里性能最好的Promise/a+规范的实现模块,Api非常齐全,功能强大,是原生Promise外的不二选择。

好处如下:

  • 避免Node.js内置Promise实现 问题,使用与所有版本兼容
  • 避免Node.js 4曾经出现的内存泄露问题
  • 内置更多扩展,timeout、 promisifyAll等,对Promise/A+规范提供了强有力的补充

限于时间关系,这里就不一一列举了,还是那句话,在学习Node.js过程中,对于Promise了解多深入都不过分。

推荐学习资料

1.3.6.4. 4)终极解决方案:Async/Await

Async/Await是异步操作的终极解决方案,Koa 2在node 7.6发布之后,立马发布了正式版本,并且推荐使用async函数来编写Koa中间件。

这里给出一段Koa 2应用里的一段代码

exports.list = async (ctx, next) => {
  try {
    let students = await Student.getAllAsync();

    await ctx.render('students/index', {
      students : students
    })
  } catch (err) {
    return ctx.api_error(err);
  }
};

它做了3件事儿

  • 通过await Student.getAllAsync();来获取所有的students信息。
  • 通过await ctx.render渲染页面
  • 由于是同步代码,使用try/catch做的异常处理

是不是非常简单,现在Eggjs里也都是这样同步的代码。

4.1 正常写法

const pkgConf = require('pkg-conf');

async function main(){
    const config = await pkgConf('unicorn');

    console.log(config.rainbow);
    //=> true
}

main();

变态写法

const pkgConf = require('pkg-conf');

(async () => {
    const config = await pkgConf('unicorn');

    console.log(config.rainbow);
    //=> true
})();

4.2 await + Promise

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require("fs"));

async function main(){
    const contents = await fs.readFileAsync("myfile.js", "utf8")
    console.log(contents);
}

main();

4.3 await + co + generator

const co = require('co');
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require("fs"));

async function main(){
   const contents = co(function* () {
      var result = yield fs.readFileAsync("myfile.js", "utf8")
      return result;
   })

    console.log(contents);
}

main();

要点

  • co的返回值是promise,所以await可以直接接co。
  • co的参数是genrator
  • 在generator里可以使用yield,而yield后面接的有5种可能,故而把这些可以yield接的方式成为yieldable,即可以yield接的。
    • Promises
    • Thunks (functions)
    • array (parallel execution)
    • objects (parallel execution)
    • Generators 和 GeneratorFunctions

由上面3中基本用法可以推出Async函数要点如下:

  • Async函数语义上非常好
  • Async不需要执行器,它本身具备执行能力,不像Generator需要co模块
  • Async函数的异常处理采用try/catch和Promise的错误处理,非常强大
  • Await接Promise,Promise自身就足够应对所有流程了,包括async函数没有纯并行处理机制,也可以采用Promise里的all和race来补齐
  • Await释放Promise的组合能力,外加co和Promise的then,几乎没有不支持的场景

综上所述

  • Async函数是趋势,如果Chrome 52. v8 5.1已经支持Async函数 ( https://github.com/nodejs/CTC/issues/7 )了,Node.js支持还会远么?
  • Async和Generator函数里都支持promise,所以promise是必须会的。
  • Generator和yield异常强大,不过不会成为主流,所以学会基本用法和promise就好了,没必要所有的都必须会。
  • co作为Generator执行器是不错的,它更好的是当做Promise 包装器,通过Generator支持yieldable,最后返回Promise,是不是有点无耻?

小结

这部分共讲了4个小点,都是极其直接的必须掌握的知识点。

  • 1) 异步流程控制学习重点
  • 2)Api写法:Error-first Callback 和 EventEmitter
  • 3)中流砥柱:Promise
  • 4)终极解决方案:Async/Await

这里再提一下关于Node.js源码阅读问题,很多人api都还没玩儿熟练就去阅读源码,这是非常不赞成的,不带着问题去读源码是比较容易迷失在大量代码中的。效果并不好。

先用明白,然后再去阅读Node.js源码,然后探寻libuv并发机制。很多人买了朴大的《深入浅出Node.js》一书,看了之后还是不太会用,不是书写的不好,而是步骤不对。

  • Node in action和了不起的Node.js是入门的绝好书籍,非常简单,各个部分都讲了,但不深入,看了之后,基本就能用起来了
  • 当你用了一段之后,你会对Node.js的运行机制好奇,为啥呢?这时候去读朴大的《深入浅出Node.js》一书就能够解惑。原因很简单,九浅一深一书是偏向底层实现原理的书,从操作系统,并发原理,node源码层层解读。如果是新手读,难免会比较郁闷。
  • 实践类的可以看看雷宗民(老雷)和赵坤(nswbmw)写的书

我一般给大家的推荐是把Node in action读上5遍10遍,入门干活足够了。剩下的就是反复实践,多写代码和npm模块就好。

目前所有的书籍几乎都有点过时了,大部分都是Node.js v0.10左右的版本的,我的新书是基于Node.js 8版本的,预计2018年3月或4月出版。别催我,真没法更快了。

目录

相关标签: nodejs