Node.js 笔记 1. 简介 Node.js 是一个开源和跨平台的 JavaScript 运行时环境。Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)
特点 
事件驱动:当事件被触发时,执行传递的回调函数 
非阻塞 I/O 模型:当执行 I/O 操作时,不会阻塞线程 
单线程 
拥有世界最大的开源库生态系统 ——npm  
 
Node.js 中文网 (nodejs.cn) 
学习 Node.js 可以深入理解服务器开发 、Web 请求和响应过程 、了解服务器端如何与客户端配合 
2. REPL 介绍 REPL 全称:Read-Eval-Print-Loop(交互式解释器)
R:读取, E:执行, P:打印,L:循环
控制台输入 node 命令进入 REPL 环境,两次 Ctrl + C 退出 REPL 环境
执行 js 文件
3. 文件读写 文件读写 :需要用到 fs 模块, 加载 fs 模块,: const fs = require('fs');
写文件 :
 fs.writeFile(file, data[, options], callback)
file: 文件路径 
data: 写入的数据 
options: 设置文件对应属性,如编码方式等, 选填 
callback:文件写入完毕后的回调函数 
 
1 2 3 4 5 6 7 8 const  fs = require ("fs" ); fs.writeFile ("./file.txt" , "Hello World!" , "utf-8" , (err ) =>  {   if  (err) {     console .log ("写文件出错,具体错误:" , err);   } else  {     console .log ("ok" );   } });
 
读文件: 
 fs.readFile(path[, options], callback)
1 2 3 4 5 6 7 8 9 const  fs = require ("fs" ); fs.readFile ("./file.txt" , "utf-8" , (err, data ) =>  {   if  (err) {     console .log ("读文件错误" );   } else  {     console .log (data);   } });
 
__dirname : 当前模块的目录名
__filename : 当前模块的文件名
path 模块 :用于文件路径的拼接
4. 编写 http 服务程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const  http = require ("http" );const  server = http.createServer (); server.on ("request" , (req, res ) =>  {   res.setHeader ("Content-Type" , "text/html;charset=utf-8" );    res.write ("Hello World! <h1>你好</h1>" );    res.end ();  }); server.listen (8080 , () =>  {   console .log ("请访问:http://localhost:8080" ); });
 
5. 根据不同请求做出不同响应 实现进入首页出来首页的结构,进入其他页面出来 404 页面。现在不支持加载 html 文件中的其他文件,如 css 文件、图片等 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const  http = require ("http" );const  fs = require ("fs" );const  path = require ("path" );const  server = http   .createServer ((req, res ) =>  {     if  (req.url  === "/"  || req.url  === "/index" ) {       fs.readFile (path.join (__dirname, "htmls" , "index.html" ), (err, data ) =>  {         if  (err) {           throw  err;         }         res.end (data);       });     } else  {       fs.readFile (path.join (__dirname, "htmls" , "404.html" ), (err, data ) =>  {         if  (err) {           throw  err;         }         res.end (data);       });     }   })   .listen ("8080" , (err ) =>  {     if  (err) {       console .log (err);     } else  {       console .log ("ok" );     }   });
 
实现加载 css 文件等,就是在判断条件中增加判断 css 的条件,并且设置响应头中的 Content-Type 为 text/css 即可,图片等文件同理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 const  http = require ("http" );const  fs = require ("fs" );const  path = require ("path" );const  server = http   .createServer ((req, res ) =>  {     if  (req.url  === "/register" ) {       fs.readFile (         path.join (__dirname, "htmls" , "register.html" ),         (err, data ) =>  {           if  (err) {             throw  err;           } else  {             res.end (data);           }         }       );     } else  if  (req.url  === "/css/register.css" ) {       fs.readFile (         path.join (__dirname, "htmls" , "css" , "register.css" ),         (err, data ) =>  {           if  (err) {             throw  err;           } else  {             res.setHeader ("Content-Type" , "text/css" );             res.end (data);           }         }       );     } else  {       fs.readFile (path.join (__dirname, "htmls" , "404.html" ), (err, data ) =>  {         if  (err) {           throw  err;         } else  {           res.end (data);         }       });     }   })   .listen (8080 , (err ) =>  {     if  (err) {       throw  err;     } else  {       console .log ("ok" );     }   });
 
通过npm install mime,然后使用 mime 模块优化上面的代码(上面的代码很多可复用的部分没有分离出来)
通过npm 官网 可以查看 mime 的用法
下面用到的用法:mime.getType(filePath)根据文件路径可以得到 Content-Type。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const  http = require ("http" );const  path = require ("path" );const  fs = require ("fs" );const  mime = require ("mime" );const  server = http   .createServer ((req, res ) =>  {     const  filePath = path.join (__dirname, "public" , req.url );     fs.readFile (filePath, (err, data ) =>  {       if  (err) {         res.end ("文件不存在 404" );       } else  {         res.setHeader (           "Content-Type" ,           mime.getType (filePath) + ";charset=utf-8;"          );         res.end (data);       }     });   })   .listen (8080 , (err ) =>  {     if  (err) {       throw  err;     } else  {       console .log ("ok" );     }   });
 
6. url 模块 第一个参数是 url,第二个参数为 true 时,可以把查询字符串的参数部分变为对象形式,如下图所示
第二个参数不是 true(默认为 false)时
7. underscore 模块 1 2 3 4 5 6 7 8 9 10 11 const  _ = require ("underscore" );const  html = "<h2><%= name %></h2>" ; const  f = _.template (html);console .log (   f ({     name : "clz" ,   }) );
 
8. events 模块 事件驱动程序 :
Node.js 使用事件驱动模型,当 web server 接收到请求,就会把请求关闭,进行处理,然后去服务下一个 web 请求。当请求完成,它会被放回处理队列,当到达队列开头,结果会被返回给用户。
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时会触发回调函数。
图片来源:菜鸟教程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const  events = require ("events" );const  eventEmitter = new  events.EventEmitter (); const  connectHandler = function  connected ( ) {   console .log ("连接成功" );   eventEmitter.emit ("data_received" ); }; eventEmitter.on ("connection" , connectHandler);  eventEmitter.on ("data_received" , () =>  {   console .log ("数据接收成功" ); }); eventEmitter.emit ("connection" ); console .log ("程序执行完毕" );
 
9. 模块系统 
图片来自菜鸟教程
在路径 Y 下执行 require(X)语句执行顺序:
如果 X 是内置模块,直接加载内置模块
 
如果 X 以’/‘开头,设置 Y 为文件根路径
 
如果 X 以’./‘或’/‘或’../‘开头
a. load_as_file(Y + X)
b. load_as_directory(Y + X)
 
寻找当前路径下有没有 node_modules 文件夹
a. 有,查看 node_modules 文件夹中有无要加载的模块
b. 没有,回到上一级查看有没有 node_modules 文件夹,直到回到项目根目录为止
 
抛出异常”not found”
 
 
load_as_file(X): 
如果 X 是一个文件,将 X 作为 JavaScript 文本加载 
如果 X.js 是一个文件,将 X.js 作为 JavaScript 文本加载 
如果 X.json 是一个文件,解析 X.json 为 JavaScript 对象并加载 
如果 X.node 是一个文件,将 X.node 作为二进制插件加载 
 
load_as_directory(Y + X): 
如果 X/package.json 是一个文件
a. 解析 X/package.json,并查找”main”字段
b. let M = X + (json main 字段)
c. load_as _file(M)
d. load_index(M)
 
load_index(X)
 
 
load_index(X): 
如果 X/index.js 是一个文件,将 X/index.js 作为 JavaScript 文本加载 
如果 X/index.json 是一个文件,解析 X/index.json 为 JavaScript 对象并加载 
如果 X/index.node 是一个文件,将 X/index.node 作为二进制插件加载 
 
10. web 模块 
使用 Node 创建 web 服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const  http = require ("http" );const  fs = require ("fs" ); http   .createServer ((req, res ) =>  {     fs.readFile (__dirname + "/index.html" , (err, data ) =>  {       if  (err) {         throw  err;       } else  {         res.writeHead (200 , {           "Contnet-Type" : "text/html" ,         });         res.write (data.toString ());       }       res.end ();     });   })   .listen (9090 , (err ) =>  {     if  (err) {       throw  err;     } else  {       console .log ("http://localhost:9090" );     }   });
 
在该目录下创建一个 index.html 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!DOCTYPE html > <html  lang ="en" >    <head >      <meta  charset ="UTF-8"  />      <meta  http-equiv ="X-UA-Compatible"  content ="IE=edge"  />      <meta  name ="viewport"  content ="width=device-width, initial-scale=1.0"  />      <title > Server</title >    </head >    <body >      <h2 > CLZ</h2 >      <p > CZH</p >    </body > </html > 
 
执行 server.js 文件
 
使用 Node 创建 web 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const  http = require ("http" );const  options = {      host : "localhost" ,   port : "9090" ,   path : "/index.html" , };const  callback = function  (res ) {      let  body = "" ;   res.on ("data" , function  (data ) {     body += data;   });   res.on ("end" , function  ( ) {     console .log (body);   }); };const  req = http.request (options, callback); req.end ();
 
新开一个终端 , 执行 client.js 文件
 
 
11. Express 框架 Express 框架的核心特性:
可以设置中间件来响应 HTTP 请求 
定义了路由表用于执行不同的 HTTP 请求 
可以通过模板传递参数来动态渲染 HTML 页面 
 
11.1 安装  
几个重要的模块
body-parser : node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据 
cookie-parser : 解析 Cookie 的工具,通过 req.cookies 可以取到传过来的 cookie,并将它们转化为对象 
multer : node.js 中间件,用于处理 enctype=”multipart/form-data”(设置表单的 MIME 编码)的表单数据 
 
11.2 Express 框架实例 实例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const  express = require ("express" );const  app = express (); app.get ("/" , (req, res ) =>  {   res.send ("Hello World!" ); });const  server = app.listen (9090 , "localhost" , function  ( ) {   let  host = server.address ().address ;   let  port = server.address ().port ;   console .log (server.address ());   console .log ("http://%s:%s" , host, port); });
 
执行以上代码后,在浏览器中访问 http://localhost:9090/ 
实例 2(路由):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const  express = require ("express" );const  app = express (); app.get ("/" , function  (req, res ) {   res.send ("Hello" ); }); app.get ("/list_user" , function  (req, res ) {   res.send ("用户列表页面" ); }); app.get ("/ab*cd" , function  (req, res ) {   res.send ("正则匹配" ); });const  server = app.listen (9090 , function  ( ) {   console .log ("http://localhost:9090" ); });
 
实例 3(静态资源):
1 2 3 4 5 6 7 8 9 10 11 12 const  express = require ("express" );const  app = express (); app.use (express.static ("public" ));  app.get ("/" , function  (req, res ) {   res.send ("Hello" ); });const  server = app.listen (9090 , function  ( ) {   console .log ("http://localhost:9090" ); });
 
12. MySQL 12.1 安装驱动  
12.2 简单连接使用数据库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const  mysql = require ("mysql" );const  connection = mysql.createConnection ({   host : "localhost" ,   user : "root" ,   password : "******" ,    database : "node_mysql" , }); connection.connect (); connection.query ("select 1 + 1 as solution" , function  (err, results, fields ) {   if  (err) {     throw  err;   }   console .log ("The solution is: "  + results[0 ].solution ); });
 
参考:Node.js 教程 | 菜鸟教程 (runoob.com)