浏览器Javascript 不能做什么?
原因是为了安全,和浏览器的运行机制有关
在开发人员能力相同的情况下编程语言的能力取决于什么?
取决于平台,
Node.js 是一个运行在Chrome V8 引擎的JavaScript 的一个运行环境
Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效
事件驱动: 任务执行,发布者,订阅者,事件驱动 ( on emit )
非阻塞: 执行某一个任务的同时也可以执行其他任务
阻塞: 执行某一个任务,这个任务如果没有执行完成,其他任务必须等待
I/O: 输入/输出( 数据库,文件系统操作等操作 )
定义: 可以运行在服务端的一个网站(站点)
种类:
web服务器( 静态服务器 ),可以运行在浏览器中的服务器
api 服务器( 后端接口 ),后端语言暴露一个数据接口,用于前端的请求
http 模块
// 1. 引入http模块(对象)
const http = reqiure('http');
//2. 通过httpP模块上的 createServer 这个api 创建一个函数
//3. 创建服务器端口和域名
const port = 8888;
const host = 'localhost';//127.0.0.1
const server = http.createServer( (request, response) => {
response.writeHead(200, { //设置响应头
'Content-Type': 'text/html;charset=UTFf8'
})
response.write('返回给客户端的数据');//向前台发送信息
response.end(); //发送已经结束
}).listen( port, host, () => {
console.log(`The server running at:http://${ host } : ${ port } `)
});
ps:因为浏览器在请求时会默认发送favicon.ico图标请求,如需阻止在http回调函数里环境里判断阻止
代码示例:
if(request.url.indexOf("favicon.ico") === -1){
return false;
};
ps:关于设置响应头解析类型的设置
"Content-type":"text/html;charset=utf-8" 解析HTML标签以及属性
"text/plain" 纯文本
"text/css" 解析css
"text/javascript" 解析js
"text/png" 解析图片
"text/json" json数据
"......"
app.get(路由路径,(路由回调函数(路由中间件),next) => { })
const express = require('express');
const app = express() //创建了一个app对象
app.get('/', (req, res, next) => {})
app.listen(port, hostname, () => { //创建一个服务器
console.log(`The server is runinng at:http://${ hostname}:${ port }`)
})
response.writeHead(200, {
'Content-Type': 'text/html;charset=UTF8'
})
response.write('<meta charset=UTF-8>')
对二进制有效:将二进制 -》 toSrgin()
借助第三方工具:
CommonJS对模块的定义主要分为:
//1. 模块定义
const student = { //可以是对象(可以传多个)、函数、字符串
name: 'meijuna',
jineng () {
console.log('I cn fly');
}
}
//2. 模块导出
module.exports = student; //安全性不高,只能到处多个
module.exports = { //更安全,批量导出
student,
fn
};
//3. 模块引用
const student = require('./xx.js'); // or
const { student, fn } = requie('./xx.js); //可以按需引用
URL模块提供了三种处理path的方法
1) 将path字符类型转成对象
left url = "http://user:pass@host.com:8080/p/a/t/h?query=string#hash";
url.parse(url,[可选布尔值],[可选项布尔值]);
{
单词解释 解析属性 属性解释
协议 protocol:"http:", 协议
斜线 slashes:true, 是否有//
认证 auth:"user:pass", 用户名与密码
主机 host:"host.com:8080", 主机
接口 port:"8080", 端口
主机名 hostname:"host.com", 域名
搞砸 hash:"#hash", 片段标识符,指向html页面某个dom元素的id
搜索 search:"?query=string", ? + 查询字符串
查询 query:"query=string", 查询字符
路径名 pathname:"/p/a/t/h", 端口号和?之间的 路径那部分
路径 path:"/p/a/t/h?query=string", pathname + search
水平基准 href:全路径url 原始路径
}
2) 将对象转成url字符串
url.format(obj)
ps:参考结合parse方法;
3) 替换或者替换(未验证)
url.resolve(from,to)
from 源地址
to 需要添加或替换的标签
ps:form源地址末尾有/就是添加 没有就是替换 具体待验证
fs 模块是专门处理操作磁盘文件,特点每个方法都有同步和异步两种 (需注意:同步以sync结尾)
读取文件:
fs.readFile("文件路径",{opt},function(err,data){
{opt}:可选项
encoding:"utf-8" 以utf-8国际编码读取文件内容
flag:"r+" read的简称,只读取文件,不存在即报错
flag:"w+" write的简称,读写文件,不存在则自动创建
err:errorObject 报错机制 一般用if判断用throw抛出错误
列:
if(err){
throw err
}
ps:console.error() 抛出错误,不影响程序执行
data:成功读取的数据,是以buffer数据二进制存储格式存在
ps:data.toString()可以转成UTF-8格式,等价于可选项中的encoding:"utf-8";
});
写入文件:
fs.writeFile("写入路径","内容数据",{opt},function(err){});
追加内容:
fs.appendFile("追加文件路径","内容数据",function(){});
读取文件夹:
fs.readdir("文件夹路径",function(err,paths){
ps:readdir是directory的缩写
paths:成功读取文件夹 用数组存储文件内容
})
创建文件夹:
fs.mkdir("文件夹路径,同时也是文件夹名称",function(err){})
拼接路径:
join(xx,xx,xxx,.)使用平台特定的分隔符,将所有给定的段连接在一起
ps:常用到的路径
__dirname 当前执行文件所在的绝对路径
querystring模块一般是对 http 请求的 URL 所带的数据进行解析处理
1) 格式数据格式化为字符串:stringify
let objData = {
name:"skye",
url:"http://skyelovedj.com"
}
let querystring = require("querystring");
querystring.stringify(objData,"分隔符","分配符")
2) 将参数字符格式为对象:
let strData = "name:skye&age=18"
let querystring = require("querystring");
querystring.parse(strData,"分隔符","分配符")
ps:分隔符和分配符是可选项
3) 编码:
querystring.escape("data") 只对符号与中文编码
4) 解码:
querystring.Unescape("data") 只对符号与中文解码
制作压缩包的模块
流
* 可读的流: 可以通过文件系统读取的流 ( 数据流 )
* 可写的流: 可以通过文件系统写入的流
* 管道流 : 连通两个文件的通道 pipe
const fs = require( 'fs' );
const zlib = require( 'zlib'); //制作压缩包的模块
//创建可读的流
const readStream = fs.createReadStream('./a.txt' );
//创建空压缩包
const gzib = zlib.createGzip();
//创建可写的流
const writeStream = fs.createWriteStream('./b.text.gz');
//创建流程
readStream
.pipe( gzib )
.pipe( writeStream );
为什么前端要使用模块化:
模块化:具有特定功能的一个对象(广义理解)
模块定义的流程:
1. 定义模块
2. 导出模块
3. 应用模块
好处:
1. 可以存储多个独立的功能块
2. 复用性高
种类:
1. ADM ( require.js )
define({
a:1,
b:2
})
require([./a.js], function( moduleA ) {
//moduleA指的是
})
define(function(require, exports, module ){
})
require('./b.js', function( moduleB ){
//moduleB就是b模块中导出的内容
})
Node 使用了 Common.js 的规范
/*目录结构: name.js index.js */
//模块定义 name.js
const nameObj = {
name: 'MeiJuna'
}
//模块导出
module.exports = nameObj;
//模块引用
const nameObj = require('./nameObj)
Node中Common.规范使用的三种类型:
1. 内置模块 (指的是挂载在Node全局对象身上的 api )
2. 自定义模块
3. 第三方模块
(前端创建一个虚拟后端服务器,后台服务器帮助我们跨域)
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
// req.headers.origin = http://127.0.0.1:5500/
app.use( cors({
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 200
}))
异步流程的任务是放在异步队列中的,
传统的原始异步
使用异步流程工具 ( 别人封装好的东西 )
es6 Promise 对象
all :依次执行完再执行
race: 谁快谁执行
es6 generator 函数
在function 关键字后加一个 *
* 通过 yield关键字定义任务
* fn().next() 来执行任务
结果返回一个对象 {value: '任务结果', done: false }
value表示 yield关键字有任务执行的结果
done 表示当前定义的所有的任务十分执行完整的一种状态
* 理解:
-多任务的定义,多任务执行
-让自己定义的多个任务一次执行,上一个任务如果没有完成,下一个任务就不会开始
function* fn() {
yield '任务1'
yield '任务2'
return '任务'
}
console.log( a.next())
console.log( a.next());
es6(7) async 函数
es6,7
* 配合关键字 await表示等待,await 任务1 执行结束才会 执行任务2
* 使用场景: 数据先请求,然后把结果赋值到变量
async function fn() {
const result = await '任务1';
console.log( '任务二' );
}
2. 箭头函数的写法
const fn1 = async () => {
const res = await '任务3';
console.log( res );
cosnole.log( '任务4' );
}
node中的 nextTick() 和 setImmediate()
nextTIck
* setImmediate
*
* 轮询: 一个事件往复执行,那么每一次执行完成,我们就认为是个轮询
* 事件轮询前, 使用nextTick
* 事件轮询后, 使用setImmediate
*
* nextTick > () => > setImmediate
第三方的 async.js 库
文档: async
cnpm i yarn -g
yarn add async -D
- parallel: 并行
- series :串行,return 数组,任务都是完整正确的,如果一个任务失败,后面的任务也会失败
主线程
并行 parallel { two: 2, one: 1 }
串行 series { one: 1, two: 2 }
结论: 主线程先执行,然后 parallel (谁快谁先走),最后 series 并行 (上个运行完,在运行下一个)
服务器
const net = require( 'net');
const hostname = "localhost";
const port = 9000;
const clients = {}; //存储每一个客户端
let count = 0; //给客户端编号
//1. 创建服务器
const server = new net.createServer()
//2. 连接客户端
server.on( 'connection', client => {
client.name = ++count; ///每个客户端起个名字
clients[ client.name ] = client; //将每一个客户端 都存储在 clients 中,key:client.name
//3. 获取客户端发来的数据
client.on( 'data', msg => {
boardcast( client, msg.toString() );
console.log( `用户 ${ client.name } 说: ${ msg.toString()}` )
});
//监听客户端的异常
client.on( 'error', error => {
console.log(`error is ${ error }`);
});
//监听客户端的下线行为
client.on( 'close', () => {
//将下线的客户端清除 --清除 clents 对象
delete clients[ client.name ]
console.log(`客户端${ client.name } closed~~`)
})
})
//4. 将客户端发来的信息展示到自己终端上( 广播 )
function boardcast( client, msg) {
// 客户端 客户端发来的消息
for(var key in clients) {
clients[ key ].write( msg );
}
}
//5. 监听服务器
server.listen( port, hostname, () =>{
console.log(`The srerver is ruuing at:http://${hostname}:${port}`)
})
客户端
/*
客户端:
1. 创建socket
2. socket连接服务器
3. 给服务器发送信息
*/
// 1. 创建socket
const net = require( 'net' );
const socket = new net.Socket();
const port = 9000;
const hostname = 'localhost';
const readline = require( 'readline' );//这是用来做命令行读取
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 2. socket连接服务器
socket.connect( port,hostname, () => {
//当我第一次连接好服务器之后,我给服务器发送一个我连接好的信息
socket.write( '欢迎xxx来到xxx的直播间' )
})
//客户端监听自己的异常
socket.on( 'error', error => {
console.log( `socket error is ${ error }` )
})
socket.on( 'close' , () => {
console.log( `socket connection closed ~~~` )
})
// 3. 给服务器发送信息
socket.on( 'data', msg => {
console.log( msg.toString() )//客户端自己显示写的内容
say()
})
function say () {
rl.question('请输入: ', ( answer ) => {
if( answer === 'bye' ){
//要进行命令行的结束
socket.destroy() //清除连接
rl.close()// 关闭命令行读取
}else{
socket.write( answer )
}
});
}
服务器
/*
主服务器
1. 通过ws模块来创建服务器
2. 服务器连接客户端
- 给客户端编号
3. 接收客户端发来的信息
4. 监听客户端下线
*/
// 1. 通过 ws模块 来创建服务器
const webSocket = require( 'ws' );
const ws = new webSocket.Server({
port: 8000,
host: '10.31.161.48'
})
// 2. 服务器连接客户端
const clients = {};
let count = 0;
ws.on( 'connection', client => {
// - 给客户端编号
client.name = ++count;
clients[ client.name ] = client
//接收客户端发来的数据
client.on( 'message', msg => {
console.log( `客户端 ${ client.name }说:${ msg }`)
boardcast( client,msg )
})
// 4. 监听客户端下线
client.on( 'close', () => {
delete clients[ client.name ]
console.log( `客户端 ${ client.name } closed~~` )
})
})
function boardcast ( client,msg ) {
for( var key in clients ){
clients[ key ].send( msg )
}
}
客户端
/*
客户端连接服务器文件
\(^o^)/~ h5 提供了一个 Socket 的全局对象
*/
const ws = new WebSocket( 'ws://10.31.161.48:8000' )
ws.onopen = () => {
ws.send( '欢迎来到xxx的直播间' )
}
ws.onmessage = ( msg ) => {
const content = document.querySelector( '#content' );
content.innerHTML += msg.data + '<br/>'
}
ws.onerror = ( error ) => {
if( error ){
console.log( error )
}
}
ws.onclose = () => {
console.log( `xxx下线了` )
}