Nodejs 基础知识 浅析
1. 模块化
①常用模块化规范
CommonJS + nodejs
AMD(Asynchronous Module Definition) + RequireJS
CMD(Common Module Definition) + SeaJS
UMD
ECMAScript 2015 Module
② CMD规范seajs
(1)seajs的基础语法:
引入sea.js插件包
创建一个test.js文件,在其中写如下代码:
define(function( require , exports , module ) {
module.exports.name = ” Tom”
module是模块对象,exports是对外接口对象(向外暴露数据的方法),name是添加在module模型对象上的属性
console.log(module.exports === exports) 此处打印结果为true
也就是exports可以相当于module.exports来使用,但值得注意的是,exports并不是module.exports本身,只是给exports这个变量赋值为module.exports,实现机制类似于:var exports = module.exports
})
创建一个main.js文件,在其中写如下代码:
define(function( require , exports , module ) {
console.log("hello world")
console.log(require(‘./test’))
通过require( )方法,将需要获取数据的文件路径传递进去,如果该文件向外暴露了数据,此处即可获取该数据 { name: “Tom” },如果没有暴露数据,此处打印结果为空对象{ },require无视流程控制语句,只要写了就会加载
})
再在页面中创建一个<script>标签,写上seajs.use("./js/main");即上述main.js文件的路径,该文件的.js后缀名写不写都可以,便可执行上述文件中的代码
(2)使用seajs加载第三方插件的兼容写法:(以Zepto为例)
在Zepto的js文件中,找到定义Zepto的位置:window.Zepto = Zepto
在这行代码下面添加define函数的兼容写法:
if( typeof define === ‘function’ &&define.cmd ){
此处全局判断,文件中是否加载了seajs,因为seajs中define函数默认添加了cmd属性,如果加载了seajs才引入define函数暴露Zepto,这样可以避免在没有引入seajs时,直接引入Zepto会找不到define方法
define(function( require , exports , module ) {
module.exports = Zepto;
}
}
2. nodejs 浅析(node:节点)
① nodejs基本介绍(在服务器端使用JavaScript)
(1)JavaScript运行时,构建在chrome V8引擎之上
(2)是一个JavaScript运行环境
(3)event-driven 事件驱动
(4)non-blocking I/O model 非阻塞I/O模型
(5)包括npm开源库生态系统
② REPL(Read-eval-print-loop):交互式解析器环境
(1)REPL的常用命令:
进入node,即进入了REPL环境,在命令窗口输入node
退出:输入.exit或者连续按ctrl+c两次
点击tab可以打印出Node.js中的所有对象
点击向上/向下可以查看历史命令
.save filename保存输入的命令
.load filename加载文件
在REPL环境下,可以用_代替上一次表达式的结果
(2)REPL中执行js代码文件
在命令窗口输入:node ./nodetest.js (需要打开的文件路径)
(3)终端/控制台(命令窗口)基础通用命令
dir 查看目录中的所有文件
cd 切换目录 切盘符直接输d:即可
cls clear screen 清理控制台显示内容
③模块作用域
nodejs本身是模块化的,具备类似seajs中的module,exports,require,使用方法也基本相同,只是不需要写在define中,直接写在js文件内即可,再在需要加载输出内容的文件中使用require请求数据即可
例如:
在test.js文件中写:
module.exports.name = { name: ”Tom” }
global.obj = { name: ”Jack” } global是node提供的类似window的全局对象
在nodetest.js文件中写:
console.log( require(‘./test’).name ); require中传入的内容是模块标识,如果是引用同级文件,必须加上./否则会认为是引用的核心模块
console.log(global.obj);
在控制台输出:node nodetest.js 输出结果为{ name: ”Tom” } { name: ”Jack” }
次案例中,module,exports,require的意义与seajs中基本一致,称为伪全局对象,即在自身模块中有全局效果,每个模块都有这几个对象,用法与seajs中相同,需要注意的是global是node提供的一个全局对象,可以在全局中获取数据,但是存在冲突的可能性,不推荐使用
node模块中还包含__filename(双下划线)和__dirname(双下划线)两个变量,
__filename:当前文件模块的绝对路径,包含当前文件的文件名和后缀
__dirname:当前文件所属的绝对路径,不包含当前文件的文件名和后缀
④全局函数(异步执行函数)
setTimeout( )、clearTimeout( )、setInterval( )、clearInterval( )
setImmediate( )、clearImmediate( )
例如:setTimeout( function(){
console.log(“异步执行”);
}) 即使不传入时间参数,里面的内容也会最后执行,起到异步的作用
⑤ commonJS规范(为JavaScript在后台功能实现定义的API规范)nodejs遵循这个规范
规范特征:
(1)每个单独的文件都是一个模块
(2)所有的代码都在自身的模块作用域中运行,不会污染全局作用域
(3)所有模块的对外接口都是module.exports对象
(4)require方法用于加载需要调用数据的模块文件
(5)模块可以多吃加载,但只会在首次加载时运行,并将运行结果进行缓存,以后再加载时,就直接读取缓存结果
(6)模块加载的顺序,按照其在代码中出现的顺序进行,边加载,边执行
⑥模块加载
(1) require查找规则
1 ) 首先判断标识符是纯字符串还是相对路径
2 ) 如果是纯字符串:表示核心模块 或者 第三方模块(包)
3 ) 如果是第三方包:package.json中指定的优先级大于index.js
4 ) 如果是相对路径,且有扩展名(.js、.html等):直接去找对应的文件即可
5 ) 如果是相对路径,没有扩展名,例如require(‘./test’):,有优先级:test.js > test.json > test.node
6 ) 如果在当前node_modules找不到:返回上一级目录找
7 ) 最好使用require(‘path’)模块控制路径,如果直接加载路径,正/、反\有时会产生分歧,产生无法加载文件的现象
(2) 核心模块(node提供的模块)具体功能查看文档
a ) fs模块(文件操作)
require(‘fs’).readFile(‘./readme.md’ , function(err , data)){
console.log(data); 读取传入的文件,以二进制的十六进制形式输出
console.log(data.toString()) 以可视文件形式输出
}
b ) os模块(系统操作)
…….等等
(2) 加载第三方模块
a ) 库加载示例:underscore库加载
使用npm安装underscore库,然后再加载
加载:require(‘./node_module/underscore/underscore.js’)
或者不用写路径直接写模块名:require(‘underscore’)
实现原理是,node在node_module目录下找到underscore文件夹,查看里面的package.json文件,加载这个json文件里面的main属性(指定该包的入口)下的文件路径,这个路径是相对于该package.json文件而言的,也可根据自己需求修改路径
b ) 自定义库加载
同理可以按照underscore的思路,将自定义库放在node_module目录下,再在自定义库中创建一个package.json文件,指定main属性的路径到需要加载的文件,最后再require(‘自定义name’),即可实现加载
(如果package.json文件中没有main字段,require方法会查找包目录下的index.js , index.json , index.node作为默认入口)
c ) node中只需在根目录创建唯一node_module目录
如果当前目录没有node_module目录,node会自动查找上级目录,如果上级也没有,会查找上上级目录,类似JS中函数作用域链,这样带来的好处是,只需要在根目录下创建唯一的node_module目录即可,不需要在创建的每个子目录下都创建node_module目录,提高库管理的效率。
引入库只需执行require(‘库name’)即可
⑦文件操作("fs”)
(1)编码(字符串与二进制0101…)转换
a ) node中支持的编码类型(不包含gbk:支持中文的编码规则)
ascii 早期的编码规则,只支持英文
utf8 支持不同国家语言的编码规则
utf16le
base64
binary
hex
b ) Buffer对象
Buffer是内存中的一个缓冲区,或者说是内存中的一个数据块
var buf = new Buffer(2) 创建2个字节的数据块
buf.write(“a”) 在上述2字节空间中,用第一个字节写a
buf.toString() 将16进制显示的Buffer对象转换为字符串显示
Buffer.concat( [buf1 , buf2 , buf3 , ……] ) Buffer拼接,传入一个Buffer对象的数组
……等等 (参考官方文档)
c ) 解决node中不支持的编码类型
引入插件包:iconv – lite 具体使用方法查看官方文档
简单示例:
var fs = require('fs');
var iconv = require('iconv-lite');
var data = iconv.encode('这是一段中文', 'gbk');
fs.writeFile('./test.txt', data, function(err) {
if (err) throw err;
});
fs.readFile('./test.txt', function(err, data) {
if (err) throw err;
console.log(data); ------ <Buffer d5 e2 ca c7 d2 bb b6 ce d6 d0 ce c4>
二进制数据(Buffer类型的对象)
var str = iconv.decode(data, 'gbk');
console.log(str); ------ “这是一段中文”
})
(2)同步和异步文件调用
a ) 同步操作:阻塞I/O操作(input/output)输入/输出端口
1 ) 会立即执行,阻塞I/O
2 ) 以同步编码的方式接受返回值
3 ) 针对同步I/O必须使用try – catch 捕获异常
4 ) 编程思路简单,易于操作
5 ) node中的文件操作(fs)API,带sync的都表示同步
b ) 异步操作:非阻塞I/O操作
1 ) 不会立即执行,会先把任务添加到事件队列,再依次执行
2 ) 必须通过回调函数的方式接收异步操作的返回值
3 ) 通过回调函数中的参数err对象,判断是否有错误
4 ) 相对于同步操作而言,编程思路复杂,不容易操作
(3)fs文件操作相关API简单示例(查看官方文档)
读文件 readFile、readFileSync
写文件 writeFile、writeFileSync
监视文件 watchFile
查看文件相关信息 stat
……等等
(4)可读流、可写流
a ) 可读流
创建可读流对象:var readStream = require(‘fs’).createReadStream(‘srcRead’)
通过可读流对象,可以监听文件读取过程,读取过程是通过chunk对象,一点一点进行读取,chunk即是每次读取的文件的大小,读取示例如下:
读取文件的总字节数:
var totalSize = require(‘fs’).statSync(‘srcRead’).size
开始监听文件过程读取:
readStream.on(‘data’ , function(chunk){
chunk是一个Buffer对象,具备length属性,length是字节的长度
由于每次只能读取chunk.length长度的字节,记录总共读取到的文件的大小:
curSize += chunk.length
通过curSize/ totalSize,可以获得已经读取的文件的百分比
})
读取结束时触发end事件:
readStream.on(‘end’, function(){
console.log(“读取结束”)
}
b ) 可写流
创建可读流对象:var writeStream = require(‘fs’).createWriteStream(‘srcWrite’)
写入数据:writeStream.write(data) data可以是字符串也可以是变量,如果将可读流中的chunk对象,传入可写流方法,可实现大文件的复制
关闭可写流:writeStream.end( )
c ) pipe(管道方法)
创建可读流、可写流对象:
var readStream = require(‘fs’).createReadStream(‘srcRead’)
var writeStream = require(‘fs’).createWriteStream(‘srcWrite’)
可读流具有pipe方法,可直接写入可写流中:
readStream.pipe(writeStream)
⑧网络编程
(1)OSI(Open System Interconnection)开放系统互联模型,将网络通信的工作分为7层
应用层:HTTP、SMTP、IMAP等
表示层:加密、解密等
会话层:通信连接、维持会话
传输层:TCP、UDP
网络层:IP
链路层:网络特有的链路接口
物理层:网络物理硬件
(2)网络操作(net)
服务器端代码示例:
var net = require('net');
创建一个网络服务器:
var server = net.createServer();
监听服务器的连接请求,设置请求处理回调函数,只要客户端连接成功就会触发connect连接事件,将当前连接的客户端封装成一个socket对象(双向数据流)
server.on('connection', function(socket) {
console.log('客户端连接');
设置客户端连接:首先启动window的Talnet客户端功能,然后在命令窗口输入telnet 127.0.0.1 3000即可看到客户端的信息,此处为”hello”
console.log('当前客户端IP地址:'+socket.remoteAddress)
console.log('当前客户端port端口号:'+socket.remotePort)
socket.write('hello client');
socket.on('data', function(data) {
console.log(data.toString())
})
})
开启服务器,并分配一个端口号进行监听,此处分配端口号3000
server.listen(3000, function() {
console.log("server is running")
console.log("please visit 127.0.0.1:3000")
});
客户端代码示例:
var net = require('net');
var client = net.createConnection(3000, '127.0.0.1');
client.on('connect', function() { 创建客户端与服务器的连接
console.log('connect success');
})
client.on('data', function(data) { data是服务器中socket.write写入的数据
var data = data.toString();
console.log(data);
if (data == "hello client") {
client.write('hello server'); 向服务器中写入数据
}
})
(3)http协议基本概念
客户端浏览器、服务器连接的简单图示:(以百度为例)
利用curl查看请求和响应报文: >表示请求报文、<表示响应报文
下载curl后,配置好环境变量后即可在CMD终端中查看报文
具体命令:curl www.baidu.com –v
三次握手:
* Rebuilt URL to: www.baidu.com/
* Trying 115.239.211.112...
* TCP_NODELAY set
* Connected to www.baidu.com (115.239.211.112) port 80 (#0)
下述部分是请求报文,
> GET / HTTP/1.1 请求首行:请求方法+请求路径+HTTP协议版本
> Host: www.baidu.com
> User-Agent: curl/7.53.1 键值对,包含当前客户端信息
> Accept: */*
> 回车换行
下述部分是响应报文
< HTTP/1.1 200 OK
< Server: bfe/1.0.8.18
< Date: Wed, 01 Mar 2017 02:01:40 GMT
< Content-Type: text/html
< Content-Length: 2381
< Last-Modified: Mon, 23 Jan 2017 13:28:28 GMT
< Connection: Keep-Alive
< ETag: "588604fc-94d"
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Pragma: no-cache
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
< Accept-Ranges: bytes
< 回车换行
<!DOCTYPE html> 响应体(index.html中的内容)
<!--STATUS OK--><html>
……
(4)node中的http模块
示例代码如下:
var http = require('http');
通过npm安装moment插件,可以获取当前时间
var moment = require('moment');
var fs = require('fs');
var server = http.createServer(); 创建http服务器
server.on('request', function(request, response) {
两个参数,request表示请求报文解析成的对象,response表示客户端对象与net中的socket基本相同
var url = request.url; request的url属性,如果没有值,默认为/
if (url == "/") {
fs.readFile(require('path').join(__dirname, 'test.html'), 'utf8', function(err, data) {
response.writeHead(200, { 设置文件类型,可以写text/plain表示任意类型
'Content-Type': 'text/html;charset=utf-8'
})
response.write('当前服务器最新时间是:' + moment().format('YYYY-MM-DD hh:mm:ss'))
response.end(data); 设置响应结束后的内容,此处渲染test.html
})
}
加载静态资源:
例如其他的css、js文件,或者img图片,需要再次发送请求,以css为例,如果test.html页面中有<link rel="stylesheet" href="/css/test.css">,则还需在node中加载该文件
else if (url == "/css/test.css") {
fs.readFile(require('path').join(__dirname, 'test.html'), 'utf8', function(err, data) {
response.writeHead(200, { 设置文件类型为css
'Content-Type': 'text/css;charset=utf-8'
})
response.end(data); 设置响应结束后的内容,此处渲染test.css
})
}
如果有大量静态资源需要加载,这样重复写else if的方法显然不合适,此时可以通过npm安装mime插件,根据url路径判断Content-Type,方法如下:
var mime = require('mime');
var url = request.url;
var statciPath = require('path').join(__dirname, url) 获取静态资源的路径
fs.readFile(statciPath, 'utf8', function(err, data) {
if(err){ return response.end(‘404 Not Found’) } 如果资源有错误,报错
(通过mime中的lookup方法获取资源的Content-Type)
var contentType = mime.lookup(statciPath)
response.writeHead(200, {
'Content-Type': contentType
})
response.end(data);
})
})
server.listen(3000, '127.0.0.1', function() { 设置端口号为3000
console.log('请访问:127.0.0.1')
})
(5)安装formidable插件可以对文件上传等操作进行管理
查考文档:https://www.npmjs.com/package/formidable
Nodejs 基础知识 浅析的更多相关文章
- 前端知识体系-NodeJS相关】NodeJS基础知识全面总结
NodeJS基础知识 1. Node的全局对象和全局变量 1.1 全局对象:所有模块都可以调用的 global:表示Node所在的全局环境,类似于浏览器的window对象. process:该对象表示 ...
- Ajax基础知识 浅析(含php基础语法知识)
1.php基础语法 后缀名为.php的文件 (1) echo 向页面中输入字符串 <?php 所有php相关代码都要写在<?php ?>这个标签之中 echo &q ...
- nodejs基础知识查缺补漏
1. 单线程.异步I/O.对比php nodejs是单线程的,但是是异步I/O,对于高并发时,它也能够快速的处理请求,100万个请求也可以承担,但是缺点是非常的耗内存,但是我们可以加大内存, 所以能用 ...
- NodeJs 基础知识
1.网站 http://nodejs.cn/ 下载最新NodeJs并且安装2. 你可以输入一个新命令“node”.使用该“node”命令有两种不同的方法.第一种不带任何参数,将打开一个交互式Shell ...
- 21.Nodejs基础知识(下)——2019年12月16日
2019年10月04日16:56:23 7. 模块 7.1 暴露一个类,字段 var bar = require("./bar.js"); var msg = "你好&q ...
- 20.Nodejs基础知识(上)——2019年12月16日
2019年12月16日18:58:55 2019年10月04日12:20:59 1. nodejs简介 Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触 ...
- ES6(ECMAScript2015) 基础知识 浅析
1.块级作用域(let) { let fruit = “apple”; } console.log(fruit) 会报错,因为{ }大括号包含的区域为块级作用域,let在其中申明的变量只能在该块中生效 ...
- Echarts 基础知识浅析
1. 引入Echarts Echarts是基于canvas的数据可视化产品,由百度公司推出 参考官方文档,引入教程示例即可,注意有两种引入方式: (1)直接引入 (2)模块化引入 2. 基本API使用 ...
- Angular1 基础知识 浅析(含锚点)
1.angular:前端js框架 https://angularjs.org ① SPA单页应用程序 通过ajax从后台获取数据,动态渲染页面,不出现白屏,提高效率,节省流量 (1)锚点值 锚点:是 ...
随机推荐
- 【Effective c++ 读书笔记】条款01 视 C++ 为一个语言联邦
一开始,C++只是 C 加上一些面向对象的特性.C++最初的名称 C with Classes 也反映了这个血缘关系. 但是,现在,当这个语言逐渐成熟,它变得更活跃更无拘束,更大胆冒险,开始接受不同于 ...
- php性能优化 --- laravel 性能优化
1.laravel官方提供了一些优化(laravel 5.* 版本): (1).关闭debug,修改 .env 的 APP_DEBUG=false (2). sudo php artisan ...
- 关于sql server 2008 r2 展开时报错:参数名:viewInfo ( Microsoft SqlServer Management SqlStudio Explorer )解决思路
今天安装了sql server 2008 R2,安装成功之后我打开软件登陆都没问题,但是一展开选项就弹出错误提示框: 参数名:viewInfo 不能为空 (Microsoft SqlServer Ma ...
- mybatis中@Param用法
用注解来简化xml配置的时候,@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中 我们先来看Mapper接口中的@Select方法 package Ma ...
- poj 2674 线性世界 弹性碰撞
弹性碰撞的题目一般都是指碰到就会掉转方向的一类题目,这里我们可以忽略掉头,仅仅看成擦肩而过,交换名字等等 题意:一条线上N只蚂蚁,每只蚂蚁速度固定,方向和坐标不同,碰头后掉头,求最后掉下去那只蚂蚁的名 ...
- PHP.26-TP框架商城应用实例-后台3-商品修改、删除
商品修改{修改页一般与添加页有百分之九十的相似度} create($_POST,Model::MODEL_UPDATE):系统内置的数据操作包括Model::MODEL_INSERT(或者1)和Mod ...
- [bzoj2733]永无乡&&[bzoj3545]Peaks
并不敢说完全会了线段树合并,只是至少知道原理写法了...还是太菜了,每天被大佬吊锤qwq 我看到的几道线段树合并都是权值线段树的合并.这个算法适用范围应该只是01线段树的. 这两道算入门题了吧... ...
- POJ 3461 Oulipo(字符串hash)
题目链接 字符串hash判断字符串是否相等. code #include<cstdio> #include<algorithm> #include<cstring> ...
- 被relativeLayout的grivate center 折腾死了
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=&q ...
- 什么是App加壳,以及App加壳的利与弊
非著名程序员涩郎 非著名程序员,字耿左直右,号涩郎,爱搞机,爱编程,是爬行在移动互联网中的一名码匠!个人微信号:loonggg,微博:涩郎,专注于移动互联网的开发和研究,本号致力于分享IT技术和程序猿 ...