Nodejs

Nodejs
 
node.js官网: https://nodejs.org/en/
node.js中文: http://nodejs.cn/
node.js社区: https://cnodejs.org/
 
Node.js简介
 
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
 
简单的说 Node.js 就是运行在服务端的 JavaScript。
 
V8引擎本身就是用于Chrome浏览器的JS解释部分,但是Ryan Dahl这哥们,把这个V8搬到了服务器上,用于做服务器的软件。
 
Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触角伸到了服务器端,可以与PHP、JSP、Python、Ruby平起平坐。
 
Node.js不是一种独立的语言,与PHP、JSP、Python、Perl、Ruby的“既是语言,也是平台”不同,Node.js使用JavaScript进行编程,运行在JavaScript引擎上(V8)。
 
与PHP、JSP、.net等相比(PHP、JSP、.net都需要运行在服务器程序上,Apache、Naginx、Tomcat、IIS。),Node.js跳过了Apache、Naginx、Tomcat、IIS等HTTP服务器,它自己不用建设在任何服务器软件之上。
 
浏览器、nodejs和其他服务器之间的关系
 
 
 
node.js特点:
 
单线程
在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。
 
Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
 
非阻塞 I/O(异步)
当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。
 
由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。
这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。
 
事件驱动
在Node中,客户端请求建立连接,提交数据等行为,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件循环”机制。
Node.js底层是C++(V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建。用事件驱动来完成服务器的任务调度,用一个线程,担负起了处理非常多的任务的使命。
 
 
 
Node.js是一个让JavaScript运行在服务器端的开发平台,所以必须首先在本机安装Node.js环境
1. 下载地址
官网术语解释
LTS 版本:Long-term Support 版本,长期支持版,即稳定版。
Current 版本:Latest Features 版本,最新版本,新特性会在该版本中最先加入。
 
2. 启动程序 node-v10.16.0-x64.msi 一直点下一步......
 
3. 在cmd中,输入 node -v 就能够查看版本号,同时,也内置了npm,通过 npm -v 查看版本号
 
4. 重启电脑,系统环境变量才会起作用。
就是在系统的任何目录下,都能运行c:\program files\nodejs里面的程序。
 
 
NPM 介绍
NPM是随同NodeJS一起安装的包管理工具,包的结构使您能够轻松跟踪依赖项和版本。
 
能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
允许用户从NPM服务器下载别人编写的第三方包到本地使用。
允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
 
生成 package.json 配置文件
$ npm init
 
$ npm init -y  跳过所有提问
 
安装包
 
本地安装(当前项目能访问到)
$ npm install 包名
 
全局安装(其他项目都能访问到)
$ npm install 包名 -global
 
缩写形式
$ npm i 包名 -g
 
项目依赖(添加到dependencies)
$ npm install 包名 -save
项目上线需要用到的包,缩写 $ npm install 包名 -S (大写)
 
开发依赖(添加到devDependencies)
$ npm install 包名 -save-dev
开发测试需要用到的包,缩写 $ npm install 包名 -D (大写)
 
清除缓存数据
npm cache verify
如报错 -4048 时使用
 
淘宝 NPM 镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
 
 
编写nodejs程序
 
之前所编写的javascript代码都是在浏览器中运行的,因此可以直接在浏览器的控制器console中编写js代码并运行。
 
现在我们编写的javascrip代码都是在Node环境中执行,执行方式有两种:
 
方式一:在window命令行环境中输入指令node并回车,进行node的交互式环境,编写javascript代码执行即可。其中node交互式环境也称之为REPL(Read Eval Print Loop-读取评估打印循环 ),按两次ctrl+c,可退出REPL环境。
 
先输入node指令,进入node的交互式环境,在输入js代码。
C:\Users\qf>node
> 2+2
 
方式二:把javascript代码写在后缀为.js的文件中
如有一个hello.js文件,在window命令行中输入node hello.js即可执行。
如在hello.js中编写以下代码:
var a = 2;
var b = 2;
console.log(a+b);
命令行中执行:node hello.js
 
注:在浏览器环境中全局对象是window,在node环境中全局对象变为global
 
 
搭建web服务器
 
 
步骤:
    1. 加载http模块
    2. 创建http服务,
    3. 服务端对象监听request 请求事件,用于监听客户端的请求
    4. 启动http服务,监听端口
 
参考代码:
1. 加载http模块 var http = require('http');
2. 创建http服务 var server = http.createServer();
3. 服务端对象监听request 请求事件,用于监听客户端的请求
server.on('request',function (req, res) {
  //req-请求对象 , res-响应对象
  //处理客户端请求逻辑
  console.log('收到请求: '+ req.url); //用户请求地址
  res.end(); //必须结束响应,否则浏览器会被挂起
});
4. 启动http服务,开始监听3000端口
server.listen(3000, function () {
  console.log('服务已经启动,请访问: http://localhost:3000 或 http://127.0.0.1:3000');
});
 
注意:
 1. 在监听request事件中,最后一定要res.end()结束响应。
 2. 浏览器显示中文可能是乱码,需设置响应头告诉浏览器显示时所使用的编码,要在res.end()之前设置
   res.setHeader("Content-type","text/plain;charset=utf-8"); // 响应为纯文本
   res.setHeader("Content-type","text/html;charset=utf-8");  //响应为html文本
 
 
或者
 
 
Node.js是服务器的程序,写的js语句,都将运行在服务器上。返回给客户的,都是纯htm已经处理好的l。
 
 
nodejs 读写文件
 
 
使用到的文件系统模块 var fs = require('fs');
 
读文件:fs.readFile(file[, options], callback)
    * 参数1:要读取的文件路径,必填。
    * 参数2:读取文件时的选项,比如:文件编码utf8。选填。
    * 参数3:文件读取完毕后的回调函数,必填。
 
读文件注意:
    * 该操作采用异步执行
    * 回调函数有两个参数,分别是err和data
    * 如果读取文件时没有指定编码,返回的是二进制数据,如指定编码utf8,会返回指定的编码数据。
    * 只要异步操作,回调函数第一个都是错误对象err优先
 
 
 
写文件:fs.writeFile(file, data[, options], callback);
    * 参数1:要写入的文件路径,必填。
    * 参数2:要写入的数据,必填。
    * 参数3:写入文件时的选项,比如:文件编码。
    * 参数4:文件写入完毕后的回调函数,必填。
 
写文件注意:
    * 该操作采用异步执行
    * 如果文件存在则替换原内容
    * 默认写入的文件编码为utf8
    * 回调函数有1个参数:err,表示在写入文件的操作过程中是否出错了。
    * 如果出错了err != null,成功时 err === null
    * 写入文件(文件不存在则自动创建)
 
注:writeFile写入文件是先把文件内容清空在写入,如果要追加写入的话可以使用appendFile函数
 
 
 
了解其他常见模块:
path模块 提供用于处理文件路径和目录路径的实用工具。
var path = require('path');
 
url模块 用于处理与解析 URL。
var url = require('url');
 
querystring 模块提供用于解析和格式化 URL 查询字符串的实用工具。
 
 
本地服务器
npm i http-server -g
cmd 进入当前目录  运行  http-server
 
CommonJS模块化规范
 
概述
node应用由模块组成,采用的commonjs模块规范。
每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。
加载某个模块,其实是加载该模块的module.exports属性,require方法用于加载模块。
 
CommonJS模块的特点:
所有代码都运行在模块作用域,不会污染全局作用域。
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。
要想让模块再次运行,必须清除缓存。
加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
模块加载的顺序,按照其在代码中出现的顺序。
 
module对象
CommonJS规范规定,每个模块内部,module变量代表当前模块。
这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。
 
module.exports属性
module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。
 
exports变量
node为每一个模块提供了一个exports变量(可以说是一个对象),指向 module.exports。
这相当于每个模块中都有一句这样的命令 var exports = module.exports;这样,在对外输出时,可以在这个变量上添加方法。
例如:exports.add = function (r){return Math.PI * r *r};
 
注意:不能把exports直接指向一个值,这样就相当于切断了 exports 和module.exports 的关系。
例如:exports=function(x){console.log(x)};
 
一个模块的对外接口,就是一个单一的值,不能使用exports输出,必须使用 module.exports输出。
例如:module.exports=function(x){console.log(x);};
 
require方法
require方法用于加载模块文件,相当于读入并执行一个js文件,然后返回该模块的exports对象,没有发现指定模块,则就会报错。
例如:example.js
exports.name = 'tom';
exports.age = 50;
在 同目录下的 demo.js 文件中
var example = require('./example.js');
console.log(example.name); // tom
console.log(example.age); // 50
或者 example.js 
function fn(){console.log(1)};
var name =  'tom'
module.exports = {fn:fn,name:name}
es6的对象简写,key 和 value 一致,可以只写一个:module.exports = {fn,name};
在 同目录下的 demo.js 文件中
var example = require('./example.js');
example.fn(); // 1
 
 
ES6 模块与 CommonJS 模块的差异
 
ES6 模块与 CommonJS 模块完全不同,它们有两个重大差异。
 
第一个差异:
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
 
第二个差异:
因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。
而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
 
下面重点解释第一个差异。
 
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个模块文件lib.js的例子。
 
// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};
上面代码输出内部变量counter和改写这个变量的内部方法incCounter。然后,在main.js里面加载这个模块。
 
// main.js
var mod = require('./lib');
 
console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 3
上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
 
// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  get counter() {
    return counter
  },
  incCounter: incCounter,
};
上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。
 
$ node main.js
3
4
 
 
 
 
 
 
 
posted @ 2019-07-01 11:26  前端小菜鸟吖  阅读(2605)  评论(0编辑  收藏  举报