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

Node.js入门

程序员文章站 2022-04-15 15:24:01
一,了解Node.js 1.简介: 基于事件驱动,可以实现异步,非阻塞IO 由于早期的网景公司和IE发布的浏览器都采用了Javascript的脚本语言,使用相当广泛,直到Google公司发布了基于Webkit内核的Chrome浏览器,并且重新编译了Javascript的虚拟引擎,命名为V8,使其运行 ......

一,了解node.js

## 1.简介:
基于事件驱动,可以实现异步,非阻塞io
由于早期的网景公司和ie发布的浏览器都采用了javascript的脚本语言,使用相当广泛,直到google公司发布了基于webkit内核的chrome浏览器,并且重新编译了javascript的虚拟引擎,命名为v8,使其运行的速度大幅度提升。
node.js的发布:ryan dahl的程序员根据需求开发一个高性能的服务器,由于google发布的v8引擎性能非常好,而javascript生来就是基于事件,可以轻松的实现回调数据而javascript的后端开发领域几乎是空白的,所以node.js被创作出来,node是节点的意思,当时的作者希望它可以构建大型分布式可扩展可伸缩的平台,每一个线程、进程甚至服务器都作为整个平台的节点
## 2.node.js的特点
#### 异步非阻塞io
同步和异步:
同步指的是在请求资源或者查询数据库或者在进行大量运算时,需要等待操作完成才能进行下一步动作,同步的代码都是按照串行顺序完成的,中间某一个环节的错误有可能会导致整个程序的退出。
异步是相对同步而言,异步仅仅是对于上面提到的动作发送一个请求,但不需要等待请求完成,即可继续进行后续的操作,而请求的结果执行是在回调函数中完成的。
在专业术语中,同步也叫串行;异步也叫并行。

node.js中大多数操作都支持异步操作进行(同时也支持同步操作进行),无论是文件读取还是网络请求亦或是数据库访问,都支持并行的异步io操作。由于异步非阻塞io的特性,node.js非常适合做高并发服务器。
#### 基于事件的回调
node.js中仿照浏览器事件的原理针对大部分异步操作都采用了事件处理,在事件中监听变化并把结果返回给回调函数。因此我们代码编写的顺序未必就是实际的执行顺序,这有可能会造成代码阅读上的障碍。在学习node.js的过程中,注意:事件回调函数的第一个形参一般都指代error(即异步处理可能发生的错误),并且应该优先处理error。

const fs = require('fs')
fs.readfile('hello.txt', (err) => {
    if (err) {
        // 这里发生了错误
        console.error(err)
        return
    }
    // 如果没有错误发生,err约定是null.
})

#### 单线程
因为浏览器内核运行javascript都是在单线程环境下执行的,因此node.js继承了javascript的单线程特性,但是目前已经拥有了实现多线程的方法:
通过web workers创建工作线程来实现多线程,并通过window.postmessage实现线程通信。
通过child_process实现和web workers类似的方式,该特性只有node.js提供。

#### 跨平台
node非常引入关注的特点还有具有跨平台特性,兼容window、linux和unix(mac的osx基于unix),底层的架构是借助libuv实现的跨平台兼容,此外libuv不仅用于node.js,也成为了许多跨平台的基础组件。

3.node.js的应用领域

虽然node.js是为了高性能服务器而开发,但它并非适用于所有领域。在当前的后端开发领域,它主要适用于以下场景:

  • io密集型业务

    天然的异步io特性让node.js非常适合大量的io请求、读写,它可以快速的处理请求并返回数据。但node.js不适合计算密集型(例如人工智能算法),这种操作通常交给c++来处理。

  • 分布式应用

    由于高效的io操作,node.js非常适合开发数据库集群。数据库的访问可以是大量io请求,只不过请求的处理需要进行密集的计算(数据库引擎来完成)。阿里巴巴利用node.js开发了nodefox

    4node.js运行时

    安装完毕node.js之后,可以在终端(windows cmd命令行或者nix终端)输入: node -v,查看node版本。出现版本号表示安装成功
    输入:node回车
    node会进入repl环境(read eval print loop:交互式解释器) ,类似 window 系统的终端或 unix/linux shell,我们可以在终端中输入命令,并接收系统的响应。
    repl可以执行:
    读取用户输入或者javascript变量声明
    执行javascript代码
    多行表达式(如 for循环)会自动通过... 来换行
    打印结果
    执行完毕后:
    ctrl + c - 退出当前终端。
    ctrl + c 按下两次 - 退出 node repl。

    5.了解npm

    node.js安装完毕后,会随同它一起安装了一个npm工具,该工具作为npm命令单独使用。

npm是一个包管理工具,它能够辅助用户远程安装其他的依赖包
用途如下:

  • 用户可以从npm仓库下载第三方包到本地使用。
  • 用户可以从npm仓库下载安装第三方命令行工具到本地使用。
  • 允许用户发布自己的包或命令行工具到npm仓库中。
    node.js默认是集成npm的,只需要在终端输入:npm -v即可打印版本号
$ npm -v
6.4.1

npm常用的命令:

1.  npm install [-args] [<@scope>/]<name>[@<version range>]
    安装第三方依赖包,例如:npm install --global @babel/core@7.6.4
2.  npm uninstall  [-args] [<@scope>/]<name>[@<version range>]:
    卸载模块,例如:npm uninstall jquery --save-optional,卸载可选阶段的依赖里的jquery
3.  npm update [-g] [<pkg>]
    更新模块。
4.  npm outdated [[<@scope>/]<pkg>]
    检查模块是否已经过时。
5.  npm ls [[<@scope>/]<pkg> ...]
    查看安装的模块。
6.  npm init [-f|--force|-y|--yes]
    在项目中引导创建一个package.json文件。
    安装包的信息可保存到项目的package.json文件中,以便后续的其它的项目开发或者他人合作使用。
7.  npm root [-g]
    查看包的安装路径
8.  管理npm的配置路径有关的命令
npm config set <key> <value> [-g|--global]
npm config get <key>
npm config delete <key>
npm config list
npm config edit
npm get <key>
npm set <key> <value> [-g|--global]
9.  npm cache verify:清理缓存,如果安装莫名报错可以考虑清空缓存。
 [清空npm缓存]
nodejs 清空 npm 缓存
npm cache clean -f


10. npm start [-- args]:启动某个脚本指令
    该命令写在package.json文件scripts的start字段中:
    "scripts": {
        "start": "gulp -ws"
    }
    可以自定义命令来配置一个服务器环境和安装一系列的必要程序,如
    此时在cmd中输入npm start命令相当于执行gulpfile.js文件自定义的watch和server命令。
11. npm stop  [-- args]:停止脚本。
12. npm restart: 重启脚本。
13. npm publish: 发布自己的模块到仓库。
14. npm version: 查看版本。
详解npm install

npm install主要功能是在当前目录下安装所需的依赖,安装的依赖包可以通过引入库的方式随意的使用。正规格式如下:其中[]中是可选的<>中表示的是自定义名称。

npm install 安装的依赖包默认存储在项目目录(需要具有package.json)的node_modules目录下。

引入依赖包时,会通过一级一级查找node_modules目录,直到找到该包。
npm install [args] [<@scope>/]<name>[@<version range>]

npm install :需要保证当前目录下存在package.json文件,基于package.json自动安装全部依赖。
npm install [args] [<@scope>/]<name>[@<version range>]中的可选参数args:
--save 或 -s :安装包信息将加到dependencies(生产阶段的依赖),开发阶段和部署阶段都会使用它。
--save-dev 或 -d <package>:安装包信息将加到devdependencies(开发阶段的依赖),只有开发阶段会使用它。
-o, –save-optional: 安装包信息将加入到optionaldependencies(可选阶段的依赖)。
-e, –save-exact: 精确安装指定模块版本。

npm安装包的几种依赖方式:

depedencies:指定应用依赖的外部包,这些依赖是应用正常发布后正常执行所需要的,**但不包含测试时和本地打包时所使用的包**
devdependencies:**只用于开发环境的包**,不用于生产环境,这些包通常是单元测试或者打包工具等,例如gulp, grunt, webpack, moca, coffee等。
peerdependencies:同等依赖,用于指定自己写的包兼容的宿主版本。
*试想一下,我们编写一个gulp的插件,而gulp却有多个主版本,我们只想兼容最新的版本,此时就可以用同等依赖(peerdependencies)来指定:*
{
    "name": "gulp-my-plugin",
    "version": "0.0.1",
    "peerdependencies": {
        "gulp": "3.x"
    }
}
*当别人使用我们的插件时,peerdependencies就会告诉明确告诉使用方,你需要安装该插件哪个宿主版本。
通常情况下,我们会在一个项目里使用一个宿主(比如gulp)的很多插件,如果相互之间存在宿主不兼容,在执行npm install时,cli会抛出错误信息来告诉我们,比如:*
npm err! peerinvalid the package gulp does not satisfy its siblings' peerdependencies requirements!
npm err! peerinvalid peer gulp-cli-config@0.1.3 wants gulp@~3.1.9
npm err! peerinvalid peer gulp-cli-users@0.1.4 wants gulp@~2.3.0
但是,假如运行命令npm install gulp-my-plugin –save-dev来安装自己写的包,会出现以下依赖图谱:
├── gulp-my-plugin@0.0.1
└── gulp@3.9.1
optionaldependencies:可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionaldependencies。**另外optionaldependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。**
bundleddependencies / bundledependencies:打包依赖,bundleddependencies是一个包含依赖包名的数组对象,在发布时会将这个对象中的包打包到最终的发布包里。**但是值得注意的是,这两个包必须先在devdependencies或dependencies声明过,否则打包会报错。**
package.json文件介绍

package.json描述了npm模块或者自定义项目的一些基本信息
如果自定义项目需要安装第三方依赖或者自己发布模块到npm仓库,都需要在项目的根目录下面加入package.json文件,文件格式如下:

{
  // 作者
  "author": {
    "name": "aseem kishore",
    "email": "aseem.kishore@gmail.com"
  },
  // 命令行文件路径
  "bin": {
    "json5": "lib/cli.js"
  },
  // 构建依赖
  "dependencies": {
    "minimist": "^1.2.0"
  },
  // 简介,用于npm 搜索
  "description": "json for humans.",
  // 开发依赖
  "devdependencies": {
    // 版本号介绍
    // version 必须完全和version一致
    // >version 必须比version大
    // >=version 同上
    // <version 同上
    // <=version 同上
    // ~version 大约一样,见semver(7)
    // 1.2.x 1.2.0, 1.2.1, 等,但不包括1.3.0
    "core-js": "^2.6.5",
    "eslint": "^5.15.3",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-node": "^8.0.1",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "regenerate": "^1.4.0",
    "rollup": "^0.64.1",
    "rollup-plugin-buble": "^0.19.6",
    "rollup-plugin-commonjs": "^9.2.1",
    "rollup-plugin-node-resolve": "^3.4.0",
    "rollup-plugin-terser": "^1.0.1",
    "sinon": "^6.3.5",
    "tap": "^12.6.0",
    "unicode-10.0.0": "^0.7.5"
  },
  // 项目官网
  "homepage": "http://json5.org/",
  // 关键字,用于npm 搜索
  "keywords": [
    "json",
    "json5",
    "es5",
    "es2015",
    "ecmascript"
  ],
  // 许可证
  "license": "mit",
  // 程序入口,import导入默认就加载这个入口
  "main": "lib/index.js",
  "module": "dist/index.mjs",
  // 包名,npm install 就依赖于这个
  "name": "json5",
  // 源码地址
  "repository": {
    "type": "git",
    "url": "git+https://github.com/json5/json5.git"
  },
  // 可用于npm start的命令。
  "scripts": {
    "build": "rollup -c",
    "build-package": "node build/package.js",
    "build-unicode": "node build/unicode.js",
    "coverage": "tap --coverage-report html test",
    "lint": "eslint --fix .",
    "prepublishonly": "npm run production",
    "preversion": "npm run production",
    "production": "npm run lint && npm test && npm run build",
    "test": "tap -rspec --100 test",
    "version": "npm run build-package && git add package.json5"
  },
  // 版本号
  "version": "2.1.1"
}

使用npm之前最好设置下npm的仓库镜像,以便提高访问速度:
npm config set registry [https://registry.npm.taobao.org](https://registry.npm.taobao.org)
下面命令验证配置是否成功:
npm config get registry
推荐:全局安装yarn
yarn是facebook官方发布的可以取代npm的的工具,使用命令的方式和npm类似(可选参数不同),能够显著提高安装依赖的速度,同时还能和npm兼容。
yarn [global][-d] add <pkg>:安装依赖包。

模块化

node.js所有的api都是基于模块发布和使用的

模块化的由来

在javascript的初期引用模块化是通过script标签来实现的,但是产生了很多的问题:全局的变量污染,无法找到源头;过多的script标签会导致很多杂乱无章的代码;使用某个库却没相关库的依赖;无法追踪到报错的位置和错误。

commonjs规范

node.js首先采用了commonjs规范,它是node.js 目前使用最广泛的模块规范,它是为了解决javascript的作用域问题而定义的模块,可以使每个模块的自身命名空间执行

commonjs使用规则

- 每个js文件就是一个模块,模块有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。每个模块内部,module变量(默认拥有)代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

- 模块必须通过 module.exports 导出对外的变量或接口。

引用

文件a.js

var a=10
module.exports=a

文件b.js

var a=require('./a.js')   ---此处为路径,a.js的路径
console.log(a)

注意
commonjs加载是同步的,因此无法按需加载

es6中的模块化

es6模块是ecma组织从语言层面提出的标准模块化api,未来完全可以取代commonjs和其他的模块化系统。
基本使用方式
文件a.js

var a=10
export default a
export const name='小明'

文件b.js

import a,{name}from'./a.js'//路径,a.js路径
console.log(a)
console.log(name)

它具有如下优势:

  • 基于编译时加载,可以让模块在编译阶段就能进行静态语法分析,从而提前预警语法错误或者做类型校验。
    注意
    es6模块默认在严格模式下执行,即默认在模块头部加入:"use strict"。

尤其注意:顶层的this指向undefined,不应该在顶层代码使用this

amd模块

基本使用方式
文件a.js

define(function(){
var a=10
module.export=a
})

文件b.js

var a=require('./a.js')//文件路径,a.js的路径
console.log(a)