初探 NodeJs

nodejs 开发基础环境

Posted by lanbery on July 9, 2019

Nodejs

Nodejs 事件驱动 VS Java 多线程

单线程、多线程、事件驱动编程对比

在单线程同步模型中,任务按照顺序执行。如果某个任务因为I/O而阻塞,其他所有的任务都必须等待,直到它完成之后它们才能依次执行。这种明确的执行顺序和串行化处理的行为是很容易推断得出的。如果任务之间并没有互相依赖的关系,但仍然需要互相等待的话这就使得程序不必要的降低了运行速度

在多线程版本中,这3个任务分别在独立的线程中执行。这些线程由操作系统来管理,在多处理器系统上可以并行处理,或者在单处理器系统上交错执行。这使得当某个线程阻塞在某个资源的同时其他线程得以继续执行。与完成类似功能的同步程序相比,这种方式更有效率,但程序员必须写代码来保护共享资源,防止其被多个线程同时访问。多线程程序更加难以推断,因为这类程序不得不通过线程同步机制如锁、可重入函数、线程局部存储或者其他机制来处理线程安全问题,如果实现不当就会导致出现微妙且令人痛不欲生的bug。

在事件驱动版本的程序中,3个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。事件驱动型程序比多线程程序更容易推断出行为,因为程序员不需要关心线程安全问题。

当我们面对如下的环境时,事件驱动模型通常是一个好的选择

程序中有许多任务,而且…任务之间高度独立(因此它们不需要互相通信,或者等待彼此)而且… 在等待事件到来时,某些任务会阻塞。 当应用程序需要在任务间共享可变的数据时,这也是一个不错的选择,因为这里不需要采用同步处理。 网络应用程序通常都有上述这些特点,这使得它们能够很好的契合事件驱动编程模型。

时间,效率 对比

单线程,多线程,事件驱动编程,有Task1,Task2,Task3三个任务,灰色表示阻塞阶段

从下图可以看出,多线程的单条线程也是会有灰色的阻塞,而事件驱动编程没有阻塞的原因,暂且大致分析如下:事件队列是由一条线程去循环队列,如果是遇到I/O阻塞了这条唯一的线程,线程可能会分配一条协程来处理,线程继续循环。

  • 进程:操作系统中分配资源的基本单位
  • 线程:操作系统中调度资源的基本单位
  • 协程:比线程更小的的执行单元,自带cpu上下文,一个协程一个栈

nodejs vs java


Nodejs 开发环境

window 下 进程查看

   netstat -ano | find "LISTENING" | find "3000"
   taskkill /f /im node.exe  # f 代表强制终止

Centos7 NodeJs

Centos 安装Nodejs

yum

yum install nodejs npm # 不推荐,不是最新版本

官网下载对应OS 编译包

操作步骤:

  • wget https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-x64.tar.xz
  • xz -d node-v*
  • tar -xf node
  • mv node* /usr/local/nodejs/v10.16 //移动到你的管理目录
  • ln -s 创建软链接 - ln -s /usr/local/nodejs/v10.16/bin/node /usr/bin/node - ln -s ***/npm /usr/bin/npm
  • complete 验证 - node -v - npm -v

NPM node package manager

方便让JavaScript开发者下载、安装、上传以及管理已经安装的包.

npm install

npm install -h # 帮助命令
npm install [<@scope>/]<pkg>@<version range>

npm install --save-dev  # 参数细节

npm install 在安装 npm 包时,有两种命令参数可以把它们的信息写入 package.json 文件,一个是npm install–save另一个是 npm install –save-dev,他们表面上的区别是–save 会把依赖包名称添加到 package.json 文件 dependencies 键下,–save-dev 则添加到 package.json 文件 devDependencies 键下,

不过这只是它们的表面区别。它们真正的区别是,npm自己的文档说dependencies是运行时依赖,devDependencies是开发时的依赖。即devDependencies 下列出的模块,是我们开发时用的,比如 我们安装 js的压缩包gulp-uglify 时,我们采用的是 “npm install –save-dev gulp-uglify ”命令安装,因为我们在发布后用不到它,而只是在我们开发才用到它。dependencies 下的模块,则是我们发布后还需要依赖的模块,譬如像jQuery库或者Angular框架类似的,我们在开发完后后肯定还要依赖它们,否则就运行不了。

npm init 初始化项目 package.json

npm ls

package.json 语法

Package.json 语法

常用的:

{
  "name": "st-koa-web",  	//最重要的就是name和version字段。
  							//他们都是必须的,如果没有就无法install
  "version": "1.0.0",
  "description": "koa-study",
  "main": "./src/app.js", 	//main字段配置一个文件名指向模块的入口程序。如果你包的名字叫foo,
  							//然后用户require("foo"),main配置的模块的exports对象会被返回。
  							//这应该是一个相对于根目录的文件路径。
  "scripts": { 				//是一个由脚本命令组成的hash对象,他们在包不同的生命周期中被执行。
  							//key是生命周期事件,value是要运行的命令
    "test": "test"
  },
  "config":{  				//hash可以用来配置用于包脚本中的跨版本参数
  	"port":"8080"
  },						//然后有一个“start”命令引用了npm_package_config_port环境变量,
  							//用户可以通过npm config set foo:port 8001来重写他
  "repository": {  			//指定你的代码存放的地方
    "type": "git",
    "url": "git@lanbery:wiki-study/st-koa-web.git"
  },
  "author": "lanbery",
  "license": "ISC",
  "dependencies": {  		//依赖是给一组包名指定版本范围的一个hash
    "koa": "^2.7.0",
    "web3": "^1.0.0-beta.55"
  }
  "peerDependencies":{} // 解决项目直接使用间接依赖package里的功能
}

NB 的scripts 配置

  {
    // ...
    "scripts": {
      "build": "node build.js"
    }
  }

build命令对应的脚本是node build.js。 命令行下使用npm run命令,就可以执行这段脚本。

$ npm run build
# 等同于执行
$ node build.js

常用的配置

常用的简写

npm start是npm run start
npm stop是npm run stop的简写
npm test是npm run test的简写
npm restart是npm run stop && npm run restart && npm run start的简写

查看 包信息

npm info <包名> //查看包信息 npm view jquery version //查看jquery版本 ------

node 引用本地未发布项目

两步:

  • cd {workPath}/{project-A} && npm link
  • cd {workPath}/{project-B} && npm link A

details

前端项目

webpack 项目结构参考

webpack 项目参考目录结构

* project
  * node_modules   			//nodejs 自己管理的配置
  * app     					//项目js文件,可细化模块
    - main.js 				// 主入口js
    - [**.js]
    - moduleA					模块A
  * public					//静态H5
    - index.html
  * build 					
    - bundle.js
    - index.html 				 build 生成 或copy

  * package.json 				// nodejs 项目依赖
  * webpack.config.js 		// 通过配置文件来使用Webpack 

Centos7 源码安装 NodeJs

获取最新发行版

https://nodejs.org/download/release/latest/node-v12.9.1-linux-ppc64le.tar.gz

wget https://nodejs.org/download/release/latest/node-v12.9.1-linux-ppc64le.tar.gz
tar xzvf node-v12.9.1-linux-ppc64le.tar.gz && cd node-v*


-----

> npm script 环境变量的使用 顺便在加个排序;

拿到项目中 package.json 中显性的变量列表

  "npm run env | grep npm_package | sort"

script 中使用
<code shell>
  echo $npm_package_name
</code>


## NPM 采坑

  - npm install --unsafe-perm -g web3 解决一堆乱七八糟错误   


### Window kill

  netstat -ano|findstr 9000

  taskkill /pid pid -f
  taskkill /im im -f   


----

## 定义项目入口(main)

> ain 字段是 package.json 中的另一种元数据功能,它可以用来指定加载的入口文件。假如你的项目是一个 npm 包,当用户安装你的包后,require('my-module') 返回的是 main 字段中所列出文件的 module.exports 属性。当不指定main 字段时,默认值是模块根目录下面的index.js 文件

## 发布文件配置(files)

> files 字段用于描述我们使用 npm publish 命令后推送到 npm 服务器的文件列表,如果指定文件夹,则文件夹内的所有内容都会包含进来。我们可以查看下载的 antd 的 package.json 的files 

```json
{
	"files":[
		"dist",
		"lib",
		"es"
	]
}

module

它是 rollup 中最早就提出的概念 — pkg.module

webpack 从版本 2 开始也可以识别 pkg.module 字段。打包工具遇到 package1 的时候,如果存在 module 字段,会优先使用,如果没找到对应的文件,则会使用 main 字段,并按照 CommonJS 规范打包。所以目前主流的打包工具(webpack, rollup)都是支持 pkg.module 的,鉴于其优点,module 字段很有可能加入 package.json 的规范之中。另外,越来越多的 npm 包已经同时支持两种模块,使用者可以根据情况自行选择,并且实现也比较简单,只是模块导出的方式

browser,module,main 字段优先级

npm 包其实又分为:只允许在客户端使用的,只允许造服务端使用的,浏览器/服务端都可以使用

如果我们需要开发一个 npm 包同时兼容支持 web端 和 server 端,需要在不同环境下加载npm包不同的入口文件,显然一个 main 字段已经不能够满足我们的需求,这就衍生出来了 module 与 browser 字段

当存在 index.mjs 和 index.js 这种同名不同后缀的文件时,import ‘./index’ 或者 require(‘./index’) 是会优先加载 index.mjs 文件的

  • main : 定义了 npm 包的入口文件,browser 环境和 node 环境均可使用
  • module : 定义 npm 包的 ESM 规范的入口文件,browser 环境和 node 环境均可使用
  • browser : 定义 npm 包在 browser 环境下的入口文件
----- lib
   |-- index.browser.js
   |-- index.browser.mjs
   |-- index.js
   |-- index.mjs

优先级依然是 browser = browser+mjs > module > browser+cjs > main

package 声明文件 types

{
	"types":'./index.d.ts'
}

注意”typings”与”types”具有相同的意义,也可以使用它

同样要注意的是如果主声明文件名是index.d.ts并且位置在包的根目录里(与index.js并列),你就不需要使用”types”属性指定了

npm的“–force“和“–legacy-peer-deps“参数

f 或 –force:将强制 npm 获取远程资源,即使磁盘上存在本地副本也是如此

–legacy-peer-deps标志是在v7中引入的,目的是绕过peerDependency自动安装;它告诉 NPM 忽略项目中引入的各个modules之间的相同modules但不同版本的问题并继续安装,保证各个引入的依赖之间对自身所使用的不同版本modules共存