1.作为一个前端工程师,为什么要学习服务端的开发?
2.市场对前端全栈的看法如何?对node的看法又是如何?
3.是否node如大厂所用的那样,只能作为中间件来使用?
4.在2019年的前端生态中,身处深水区后前端的时代node又扮演什么样的角色?
服务器端开发语言有很多,为什么要选择nodejs
node.js,也叫作node,或者nodejs,指的都是一个东西。
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,nodejs允许javascript代码运行在服务端
1. nodejs不是一门新的编程语言,nodejs是在服务端运行javascript的运行环境(说白了还是javascript)
2. 运行环境:写得程序想要运行必须要有对应的运行环境
java与tomcat
php代码必须要有apache服务器(LAMP...) linux+apache+mysql+php
在web端,浏览器就是javascript的运行环境(Webkit,Trident,Gecko,Presto,Blink)
在node端,nodejs就是javascript的运行环境
2. javascript并不只是能运行在浏览器端,浏览器端能够运行js是因为浏览器有js解析器,因此只需要有js解析器,任何软件都可以运行js。
3. nodejs可以在服务端运行js,因为nodejs是基于chrome v8的js引擎。
nodejs的本质:不是一门新的编程语言,nodejs是javascript运行在服务端的运行环境,编程语言还是javascript
相同点:nodejs与浏览器都是javascript的运行环境,都能够解析js程序。对于ECMAScript语法来说,在nodejs和浏览器中都能运行。
不同点:nodejs无法使用DOM和BOM的操作,浏览器无法执行nodejs中的文件操作等功能
原理:nodeJS之所以不能使用DOM和BOM操作,是因为没有顶层对象window和BOM对象,当然就不能调用它们上面的WEBAPI,而浏览器端因为没有对系统级操作的封装,所以也不能使用nodeJS等API功能!
思考:
下载地址
官网术语解释
查看node版本
node -v
查看npm版本
npm -v
开启服务器
npm start
运行node
node helloNode.js
helloworld.js
console.log('hello nodejs')
cmd
node 文件名.js
即可terminal
插件,直接在vscode中执行,terminal插件可以让我们方便调试程序,直接在vscode上面打开终端(黑窗口)node helloworld.js
注意:在nodejs中是无法使用DOM和BOM的内容的,因此document, window
等内容是无法使用的。
Node.js 中的全局对象(顶层对象)是
global
, 类似于浏览器中的window
常用的global属性
console: 用于打印日志
setTimeout/clearTimeout: 设置清除延时器
setInterval/clearInterval: 设置清除定时器
__dirname: 当前文件的路径,不包括文件名
__filename: 获取当前文件的路径,包括文件名
//与模块化相关的,模块化的时候会用到
require
exports
module
fs模块是nodejs中最常用的一个模块,因此掌握fs模块非常的有必要,fs模块的方法非常多,用到了哪个查哪个即可。
文档地址:http://nodejs.cn/api/fs.html
在nodejs中,提供了fs模块,这是node的核心模块
注意:
const fs = require('fs');
语法:fs.readFile(path[, options], callback)
方式一:不传编码参数
//参数1: 文件的名字(读哪个文件)
//参数2: 读取文件的回调函数
//参数1:错误对象,如果读取失败,err会包含错误信息,如果读取成功,err是null
//参数2:读取成功后的数据(是一个Buffer对象)
//ES5
fs.readFile('data.txt', function(err, data){
console.log(err);
console.log(data);
});
//ES6
fs.readFile('data.txt',(err,data)=>{
console.log(err);
console.log(data);
})
方式二:传编码参数
//参数1: 文件的路径(读哪个文件)
//参数2: 编码,如果设置了,返回一个字符串,如果没有设置,会返回一个buffer对象
//参数3: 回调函数
//es5
fs.readFile('data.txt', 'utf8',function(err, data){
console.log(err);
console.log(data);
});
//es6
fs.readFile('data.txt','utf8',(err,data)=>{
console.log(err);
console.log(data);
})
关于Buffer对象
1. Buffer对象是Nodejs用于处理二进制数据的。
2. 其实任意的数据在计算机底层都是二进制数据,因为计算机只认识二进制。
3. 所以读取任意的文件,返回的结果都是二进制数据,即Buffer对象
4. Buffer对象可以调用toString()方法转换成字符串。
语法:fs.writeFile(file, data[, options], callback)
//参数1:写入的文件名(如果文件不存在,会自动创建),有读就有写
//参数2:写入的文件内容(注意:写入的内容会覆盖以前的内容)
//参数3:写文件后的回调函数
//ES5
fs.writeFile('data.txt', 'hello world, 我爱node!', function(err){
if(err) {
return console.log('写入文件失败', err);
}
console.log('文件写入成功');
});
//ES6
fs.writeFile('data.txt','hello world,我爱node!',(err)=>{
if(err)throw err;
console.log('文件写入成功');
})
注意:
语法:fs.appendFile(path, data[, options], callback)
//参数1:追加的文件名(如果文件不存在,会自动创建)
//参数2:追加的文件内容(注意:写入的内容会覆盖以前的内容)
//参数3:追加文件后的回调函数
//ES5
fs.appendFile('data.txt', '我是追加的内容', function(err){
if(err) {
return console.log('追加文件内容失败');
}
console.log('追加文件内容成功');
})
//ES6
fs.appendFile('data.txt','我是追加的内容',(err)=>{
if(err)throw err;
console.log('追加文件内容成功');
})
如果没有appendFile,通过readFile与writeFile其实也可以实现
fs中所有的文件操作,都提供了异步和同步两种方式
异步方式:不会阻塞代码的执行
//异步方式
const fs = require('fs');
console.log('111');
fs.readFile('data.txt', 'utf8', function(err, data){
if(err) {
return console.log('读取文件失败', err);
}
console.log(data);
});
console.log('222');
同步方式:会阻塞代码的执行
//同步方式 会排队
console.log(111);
var result = fs.readFileSync('2.txt', 'utf-8');
console.log(result);
console.log(222);
总结:同步操作使用虽然简单,但是会影响性能,因此尽量使用异步方法,尤其是在工作过程中。
方法有很多,但是用起来都非常的简单,要学会查文档
文档:http://nodejs.cn/api/fs.html
方法名 | 描述 |
---|---|
fs.readFile(path, callback) |
读取文件内容(异步) |
fs.readFileSync(path) |
读取文件内容(同步) |
fs.writeFile(path, data, callback) |
写入文件内容(异步) |
fs.writeFileSync(path, data) |
写入文件内容(同步) |
fs.appendFile(path, data, callback) |
追加文件内容(异步) |
fs.appendFileSync(path, data) |
追加文件内容(同步) |
fs.rename(oldPath, newPath, callback) |
重命名文件(异步) |
fs.renameSync(oldPath, newPath) |
重命名文件(同步) |
fs.unlink(path, callback) |
删除文件(异步) |
fs.unlinkSync(path) |
删除文件(同步) |
fs.mkdir(path, mode, callback) |
创建文件夹(异步) |
fs.mkdirSync(path, mode) |
创建文件夹(同步) |
fs.rmdir(path, callback) |
删除文件夹(异步) |
fs.rmdirSync(path) |
删除文件夹(同步) |
fs.readdir(path, option, callback) |
读取文件夹内容(异步) |
fs.readdirSync(path, option) |
读取文件夹内容(同步) |
fs.stat(path, callback) |
查看文件状态(异步) |
fs.statSync(path) |
查看文件状态(同步) |
在读写文件的时候,文件路径可以写相对路径或者绝对路径
//data.txt是相对路径,读取当前目录下的data.txt, 相对路径相对的是指向node命令的路径
//如果node命令不是在当前目录下执行就会报错, 在当前执行node命令的目录下查找data.txt,找不到
fs.readFile("data.txt", "utf8", function(err, data) {
if(err) {
console.log("读取文件失败", err);
}
console.log(data);
});
相对路径:相对于执行node命令的路径,这是个坑
绝对路径:__dirname
: 当前文件的目录,__filename
: 当前文件的目录,包含文件名
关于路径,在linux系统中,路径分隔符使用的是
/
,但是在windows系统中,路径使用的\
在我们拼写路径的时候会带来很多的麻烦,经常会出现windows下写的代码,在linux操作系统下执行不了,path模块就是为了解决这个问题而存在的。
常用方法:
path.join();//拼接路径
//windows系统下
> path.join("abc","def","gg", "index.html")
"abc\def\gg\a.html"
//linux系统下
> path.join("abc","def","gg", "index.html")
'abc/def/gg/index.html'
path.basename(path[, ext]) 返回文件的最后一部分
path.dirname(path) 返回路径的目录名
path.extname(path) 获取路径的扩展名
var path = require("path");
var temp = "abc\\def\\gg\\a.html";
console.log(path.basename(temp));//a.html
console.log(path.dirname(temp));//abc\def\gg
console.log(path.extname(temp));//.html
方法名 | 描述 |
---|---|
path.basename(path[, ext]) |
返回文件的最后一部分 |
path.dirname(path) |
返回路径的目录名 |
path.extname(path) |
获取路径的扩展名 |
path.isAbsolute(path) |
判断目录是否是绝对路径 |
path.join([...paths]) |
将所有的path片段拼接成一个规范的路径 |
path.normalize(path) |
规范化路径 |
path.parse(path) |
将一个路径解析成一个path对象 |
path.format(pathObj) |
讲一个path对象解析成一个规范的路径 |
必须知道
1- 输入网址浏览器的请求过程
2- http协议的构成
//1. 导入http模块,http模块是node的核心模块,作用是用来创建http服务器的。
const http = require('http');
//2. 创建服务器
let server = http.createServer();
//3. 服务器处理请求
//ES5
server.on('request', function() {
console.log('我接收到请求了');
});
//ES6
server.on('request',()=>console.log('我接收到请求了'););
//4. 启动服务器,监听某个端口
//ES5
server.listen(4396, function(){
console.log('服务器启动成功了, 请访问: http://localhost:9999');
});
//ES6
server.listen(4396,()=>console.log('服务器启动成功了, 请访问: http://localhost:9999'););
详细说明
文档地址:http://nodejs.cn/api/http.html#http_message_headers
常见属性:
headers: 所有的请求头信息
method: 请求的方式
url: 请求的地址
注意:在发送请求的时候,可能会出现两次请求的情况,这是因为谷歌浏览器会自动增加一个favicon.ico
的请求。
小结:request对象中,常用的就是method和url两个参数
文档地址:http://nodejs.cn/api/http.html#http_class_http_serverresponse
常见的属性和方法:
res.write(data): 给浏览器发送请求体,可以调用多次,从而提供连续的请求体
res.end(); 通知服务器,所有响应头和响应主体都已被发送,即服务器将其视为已完成。
res.end(data); 结束请求,并且响应一段内容,相当于res.write(data) + res.end()
res.statusCode: 响应的的状态码 200 404 500
res.statusMessage: 响应的状态信息, OK Not Found ,会根据statusCode自动设置(后台也可以手动修改)。
res.setHeader(name, value); 设置响应头信息, 比如content-type
res.writeHead(statusCode, statusMessage, options); 设置响应头,同时可以设置状态码和状态信息。
注意:必须先设置响应头,才能设置响应。
//es5
server.on('request', function(req, res) {
var url = req.url
if(url === '/') {
fs.readFile('./index.html', function(err, data) {
if(err) {
return res.end('您访问的资源不存在~')
}
res.end(data)
})
}
})
//es6
server.on('request',(req,res)=>{
let url = req.url;
if(url === '/'){
fs.readFile('./index.html',(err,data)=>{
if(err){
return res.end('您访问的资源不存在~')
}
res.end(data)
})
}
})
npm i mime
const mime = require('mime')
// 获取路径对应的MIME类型
mime.getType('txt') // ⇨ 'text/plain'
// 根据MIME获取到文件后缀名
mime.getExtension('text/plain') // ⇨ 'txt'
1. npm 是node的包管理工具,
2. 它是世界上最大的软件注册表,每星期大约有 30 亿次的下载量,包含超过 600000 个 包(package) (即,代码模块)。
3. 来自各大洲的开源软件开发者使用 npm 互相分享和借鉴。包的结构使您能够轻松跟踪依赖项和版本。
npm
来快速安装开发中使用的包npm
npm init; //这个命令用于初始化一个包,创建一个package.json文件,我们的项目都应该先执行npm init
npm init -y; //快速的初始化一个包, 不能是一个中文名
npm install 包名; //安装指定的包名的最新版本到项目中
npm install 包名@版本号; //安装指定包的指定版本
npm i 包名; //简写
npm uninstall 包名; //卸载已经安装的包
npm cache clean -f // 如果npm安装失败了,可以用这个命令来清除缓存
package.json文件,包(项目)描述文件,用来管理组织一个包(项目),它是一个纯JSON格式的。
npm init
或者npm init -y
package.json
文件进行描述npm install
直接安装项目所有的依赖项{
"name": "03-npm", //描述了包的名字,不能有中文
"version": "1.0.0", //描述了包的的版本信息, x.y.z 如果只是修复bug,需要更新Z位。如果是新增了功能,但是向下兼容,需要更新Y位。如果有大变动,向下不兼容,需要更新X位。
"description": "", //包的描述信息
"main": "index.js", //入口文件(模块化加载规则的时候详细的讲)
"scripts": { //配置一些脚本,在vue的时候会用到,现在体会不到
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [], //关键字(方便搜索)
"author": "", //作者的信息
"license": "ISC", //许可证,开源协议
"dependencies": { //重要,项目的依赖, 方便代码的共享 通过 npm install可以直接安装所有的依赖项
"bootstrap": "^3.3.7",
"jquery": "^3.3.1"
}
}
注意:一个合法的package.json,必须要有name和version两个属性
有两种方式用来安装 npm 包:本地安装和全局安装。选用哪种方式来安装,取决于你如何使用这个包。
require
加载,那么你应该选择本地安装,这种方式也是 npm install
命令的默认行为。// 全局安装,会把npm包安装到C:\Users\HUCC\AppData\Roaming\npm目录下,作为命令行工具使用
npm install -g 包名;
//本地安装,会把npm包安装到当前项目的node_modules文件中,作为项目的依赖
npm install 包名;
npm i -g nrm
# 带*表示当前正在使用的地址
# 查看仓库地址列表
nrm ls
# 切换仓库地址
nrm use taobao
npm i -g nodemon
nodemon app.js
运行node程序npm install art-template
// 基于模板路径渲染模板
//参数1:文件的路径
//参数2:数据
//返回值:返回渲染后的内容
// template(filename, data)
let html = template(path.join(__dirname, "pages", "index.html"), {name:"大吉大利,今晚吃鸡"});
注意点:文件的路径必须是绝对路径
// 导入url模块
const url = require('url')
// 解析 URL 字符串并返回一个 URL 对象
// 第一个参数:表示要解析的URL字符串
// 第二个参数:是否将query属性(查询参数)解析为一个对象,如果为:true,则query是一个对象
let ret = url.parse('http://localhost:3000/details?id=1&name=jack', true)
console.log(ret.query) // { id: '1', name: 'jack' }
res.writeHead(302, {
'Location': '/'
})
res.end()
// 接受POST参数
let postData = []
// data事件:用来接受客户端发送过来的POST请求数据
let result = "";
req.on('data', function (chunk) {
result += chunk;
})
// end事件:当POST数据接收完毕时,触发
req.on('end', function () {
cosnole.log(result);
})
// foo=bar&abc=xyz&abc=123
const querystring = require('querystring')
// 将查询参数转化为对象
// 第一个参数: 要解析的 URL 查询字符串
querystring.parse('foo=bar&abc=xyz') // { foo: 'bar', abc: 'xyz' }
以通过HTTP状态码让浏览器中的页面重定向
res.writeHead(302, {
'Location': '/'
})
res.end()
// 接受POST参数
var postData = []
// data事件:用来接受客户端发送过来的POST请求数据
let result = "";
req.on('data', function (chunk) {
result += chunk;
})
// end事件:当POST数据接收完毕时,触发
req.on('end', function () {
cosnole.log(result);
})
// foo=bar&abc=xyz&abc=123
const querystring = require('querystring')
// 将查询参数转化为对象
// 第一个参数: 要解析的 URL 查询字符串
querystring.parse('foo=bar&abc=xyz') // { foo: 'bar', abc: 'xyz' }