JS笔记(21): NODE

1、关于node

1) NODE概念

基于V8引擎(谷歌浏览器的引擎)渲染JS的工具或者环境javascript

  • 安装node(到node官网http://nodejs.cn/下载便可)
  • 把js代码放到node环境中执行

2) NODE安装完以后

  • 当前电脑后自动安装了npm(node Package Managernode模块管理器):一个js模块(全部封装好可供其余人调取使用的称之为模块或者包)管理的工具,基于npm能够安装下载js模块
  • 他会生成node执行的命令(能够在DOS窗口或者终端命令中执行):node xxx.js

3) 如何在NODE中渲染和解析JS

  • REPL模式:Read-Evaluate-Print-Loop 输入-求值-输出-循环
  • 直接基于node来执行JS文件
    • 在命令窗口中执行(DOS窗口 & 终端窗口)

多数人把node称之为后台编程语言,是由于:css

  • 1)咱们能够把node安装在服务器上
  • 2)咱们能够把编写的js代码放到服务器上,经过node执行(咱们可使用js来操做服务器,换句话说,使用js来实现服务器端的一些功能操做)

4) NODE的优点和特色:

传统后台语言:JAVA/Python/PHP/C#html

  • 单线程
  • 基于V8引擎渲染:快
  • 异步无阻塞的I/O操做:I=>input O=>ouput 对文件的读写
  • Event-driven事件驱动:相似于发布订阅或者回调函数
  • JS运行在客户端浏览器中=>前端
    • 浏览器给js提供不少全局的属性和方法 window.setTimeout...
  • JS运行在服务器端的node中=>后台
    • NODE也给js提供不少内置的属性和方法:http/fs/url/path...等对象中都提供不少API供js操做
  • 前端(浏览器运行js)是限制I/O操做的
    • input type='file' 这种算是I/O操做,可是须要用户手动选择(并且仅仅是读取不是写入)
  • 后端(node中运行js) 不限制I/O操做

5) node中的模块

node自己是基于commonJS模块规范设计的,因此模块式node的组成前端

  • 内置模块:node天生提供的js调取使用的
  • 第三方模块:别人写好的,咱们能够基于npm安装使用
  • 自定义模块:本身建立的一些模块

2、CommonJS规范

参考: CommonJS:模块设计思想(AMD/CMD/ES6 MOUDLE 都是模块化设计思想)java

  • CommonJS规定,每个js都是一个单独的模块(模块是私有的:里面涉及的值和变量以及函数都是私有的,和其余js文件中的内容是不冲突的)
  • CommonJS中能够容许模块中的方法互相的调用
    • B模块中想要调取A模块中的方法
    • => A导出
    • => B导入

1) 导出

CommonJS给每个模块(每个js)中都设置了内置的变量/属性/方法node

  • module: 表明当前这个模块对象[object]
  • module.exports: 模块的这个属性是用来导出属性方法的[object]
  • exports: 是内置的一个变量,也是用来导出当前模块属性方法的,虽然和module.exports不是一个东西,可是对应的值是一个(module.exports=exports 值都是对象)

2) 导入

  • require: CommonJS提供的内置变量,用来导入模块的(其实导入的是moudle.exports暴露出来的东西)
    • 导入的值是对象[object]

3) require导入的时候:

  • 首先把about_node.js模块中的代码自上而下执行,把exports对应对内存导入进来,因此接受的结果是一个对象
  • require是一个同步操做:只有把导入的模块代码执行完成,才能够获取值,而后继续执行本模块下面的代码
  • let temp1 = require('./about_node'); //=> ./ 是特地指定当前目录中的某个模块(.js能够省略)

4) require导入规则:

  • require('./xxx') 或者../xxx 或者 /xxx

这种本身制定的路径的模式,都是为了导入自定义的模块,换句话说,想要导入自定义的模块,必须加路径jquery

  • require('./xxx')

首先到当前项目中的node_modules中查找是否存在这个模块,不存在找node提供的内置模块(导入第三方或者内置的)web

5) CommonJS的特色:

  • 全部代码都运行在模块做用域,不会污染全局做用域(每个模块都是私有的,包括里面全部的东西也都是私有的,不会和其余模块产生干扰)
  • 模块能够屡次加载,可是只会在第一次加载时运行一次,而后运行结果就被缓存了,之后再加载,就直接读取缓存结果,要想让模块再次运行,必须清除缓存(为了保证性能,减小模块代码重复执行的次数)
  • 模块加载的顺序,按照其在代码中出现的顺序,CommonJS规范加载模块是同步的,只有加载完成,才能执行后面的操做

3、内置变量__dirname & __filename

  • __dirname: 模块中这个内置变量是当前模块所在的绝对路径(具体到盘符:物理路径)
    • console.log(__dirname)
    • C:\Users\lenovo\Desktop\notes\NODE
  • __filename: 相对于_dirname来说,多了模块名称 (即对了文件名称)
    • C:\Users\lenovo\Desktop\notes\NODE\about_node.js

示例

// about_node.js
let a = 12;
let fn = b => {
    return a * b
}
// console.log(1)
// setTimeout(()=>{
// console.log(1.5)
// },1000)
exports.fn = fn; // 把当前模块私有的函数放到exports导出对象中(赋值给他的某一个属性),这样在其余模块中,能够基于require导入进来使用 <=> moudle.exports.fn = fn
// console.log(2)

console.log(__dirname); //C:\Users\lenovo\Desktop\notes\NODE
console.log(__filename) //C:\Users\lenovo\Desktop\notes\NODE\about_node.js
复制代码
// about_node2.js
let a = 2;
let fn = b => {
    return a / b
}
let temp1 = require('./about_node'); // ./ 是特地指定当前目录中的某个模块(.js能够省略)
// console.log(3); // 1 2 3 先把about_node.js中的代码所有执行完,再执行about_node2.js中的代码
// // 若是加定时器 1 2 3 1.5
// console.log(temp1); //此时temp1是个对象 {fn:...}
console.log(temp1.fn(10)); //120 用的是about_node.js中的变量a和fn

// // 第二次并无把about_node.js执行,由于第一次执行把导出的结果缓存了 但不多写两次
// temp1 = require('./about_node');
// console.log(temp1.fn(10)); //120
复制代码

4、fs内置模块

【内置模块fs:实现I/O操做】ajax

经常使用方法:sql

  • fs.mkdir / fs.mkdirSync:建立文件夹 有Sync的是同步建立,反之是异步,想要实现无阻塞I/O操做,咱们通常用异步完成 fs.mkdir(path,callback) fs.mkdirSync(path)`
  • fs.readsir / fs.readdirSync:读取文件目录中的内容
  • fs.rmdir / fs.rmdirSync:删除文件夹(若是文件夹中有内容不能删除)
  • fs.readFile:读取文件中内容
  • fs.writeFile:向文件中写入内容(覆盖写入:写入的新内容会替换原有内容)
  • fs.appendFile:追加写入新内容,原有内容还在
  • fs.copyFile:拷贝文件到新的位置
  • fs.unlink:删除文件
let fs = require('fs');

//建立文件夹 同步会形成阻塞,通常用异步
fs.mkdir('./less',(err)=>{
    if(err){
        console.log(err);
        return;
    }
    console.log('ok');
});
console.log(1);

//读取文件目录 异步
fs.readdir('./',(err,result)=>{
    if(err){、
        // console.log(err);
        return;
    };
    console.log(result); // 当前文件目录 ['less', 'module_fs.js'] 返回结果是一个数组
});

//删除文件夹 (必须保证文件夹是空的)
fs.rmdir('./less',err=>{
    if(err){
        console.log(err);
        return;
    }
    console.log('ok');
})
/* 若是文件夹中有内容 则会报错{ [Error: ENOTEMPTY: directory not empty, rmdir 'C:\Users\lenovo\Desktop\notes\NODE\module_fs\less'] */

// 读取文件内容
fs.readFile('./less/less.js','utf-8',(err,result)=>{
    if(err){
        // console.log(err);
        return;
    }
    console.log(result);//文件内容(字符串格式) setTimeout(()=>{console.log(123) },1000)
    // 不设置utf-8编码格式,读取出来的是buffer格式的数据,设置事后是字符串格式数据
})

// 向文件中写入内容(覆盖写入)
fs.writeFile('./less/less.js','哈哈','utf-8',(err)=>{
    //第二个参数是文件写入的内容 会覆盖原内容
})

// 向文件中写入内容(追加写入)
fs.appendFile('./less/less.js','嘿嘿','utf-8',(err)=>{
    //第二个参数是文件写入的内容 追加在原内容后
})

// 删除文件
fs.unlink('./less/less.js',(err)=>{
    if(err){
        return;
    }
    console.log('ok')
})
复制代码

5、url内置模块

【url内置模块】

url.parse(url[,flag]):

  • 把一个url地址进行解析,把地址中的每一部分按照对象键值对的方式存储起来
  • 第二个参数默认为false,设置为true能够把问号传参的部分也解析为对象键值对的方式
    • 第二个参数false/true区别: query: [Object: null prototype] { from: 'qq', lx: 'stu' },

Url {

  • protocol: 'http:', //=>协议
  • slashes: true, //=>是否有双斜线
  • auth: null, //=>
  • host: 'baidu.com', //=>域名+端口
  • port: null, //=>端口
  • hostname: 'baidu.com', //=>域名
  • hash: '#video', //=>哈希值
  • search: '?from=qq&lx=stu', //=> 问号传参[string]
  • query: 'from=qq&lx=stu', //=>问号传参[string] 不包含问号
  • pathname: '/', //=> 请求资源的路径名称
  • path: '/?from=qq&lx=stu', //=>pathname + search
  • href: 'baidu.com/?from=qq&am…' //=> url地址 }
let url = require('url');
console.log(url.parse('http://baidu.com?from=qq&lx=stu#video',true));
// 返回一个url对象
复制代码

6、http内置模块

【http内置模块】

服务器端任务

  • 1.建立服务(指定端口的web服务器)
  • 2.接收客户端的请求信息,而且进行解析处理,把须要的内容获取到,而且响应给客户端

注意:基于node建立后台程序,咱们通常都建立一个server模块,在模块中实现建立web服务,和对于请求的处理(通常会把server模块放到当前项目的根目录下)

//导入内置模块
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');

//建立web服务 
let port = 80;
let server = http.createServer((req,res)=>{
    /* 当服务建立成功,而且客户端向当前服务发送了请求才会执行回调函数,而且发送一次请求,回调函数就会触发执行一次 客户端如何向建立的服务器发送请求? 对应好协议、域名、端口等信息,在浏览器中或者ajax等中发送请求便可 http://localhost:80/... 服务在电脑上,localhost本机域名,也就是本机的客户端服务器,访问本机的服务器端程序(也就是本身的电脑既是客户端又是服务器端) http://内网ip:80/... IP作域名访问,若是是内网IP,相同局域网下的用户能够访问这个服务,若是是外网IP,全部能联网的基本上均可以访问这个服务(局域网下访问,须要互相关掉防火墙) 查看内网IP:在CMD中输入ipconfig => 172.18.0.80 localhost:80/ 等同于 172.18.0.80:80/ */ 
    console.log('hello world!');
});

server.listen(port,()=>{
    //回调函数:当服务建立成功,而且端口号也已经监听成功后,触发的回调函数
    console.log(`server is success,listen${port}!`); // server is success,listen80!
});//监听一个端口 [0~65535]
//http.createServer().linten(80);

// 当服务建立成功,命令行中会一直存在光标闪烁,证实服务器正在运行中(必定要保证服务试运行的),ctrl+c => 结束运行服务

复制代码

1) 关于参数 req和res

两个参数

    1. req:require 请求对象,包含了客户端的请求信息(不包括hash值)
    • req.url 存储的是请求资源的路径地址以及问号传参
    • req.method 客户端请求方式
    • req.headers 客户端的请求头信息(是一个对象)
    1. res:response 响应对象,包含了一些属性和方法,可让服务器端返回给客户端内容
    • res.write 基于这个方法,服务器端能够向客户端返回内容
    • res.end 结束响应 -res.writeHead 重写响应头信息 (是一个对象)
      res.writeHead(200,{
          'content-Type':'text/plain;charset=utf-8'
          // text/plain 纯文本类型
      })
      复制代码
    • res.setHeader 重写响应头信息 (不用写状态码) res.setHeader('Content-type','text/html; charset=utf-8');

2) 关于req.url: 把请求的url地址中,路径名称 和 问号传参 分别解析出来

用url模块中的parse url.parse(req.url)

// 把url中的路径地址和问号传参分别解析
let {pathname,query} = url.parse(req.url,true)
console.log(pathname,query);
/* /index.html [Object: null prototype] { uesr: 'tom', name: 'haha' } */
复制代码
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');

//建立web服务 
let port = 8080;
// let handle = function handle(req,res){
    
// }
// http.createServer(handle).listen(port);

let server = http.createServer((req,res)=>{
    // console.log(url,method,headers);
    // // 获取请求头中某个具体信息
    // console.log(headers['user-agent']);
    /* /?user=tom GET 请求头:{ host: 'localhost:8080', connection: 'keep-alive', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9' } */

    // res.write('hello world!');
    // res.end('hello world!'); //表示服务器端返回字符串内容并结束响应 通常返回的是string或者buffer格式的数据

    //重写响应头信息 是一个对象 (中文设置)
    /* 对象有两个参数 1. HTTP状态码 2.'content-Type':'text/plain;charset=utf-8' 解决中文乱码问题 */
    res.writeHead(200,{
       'content-Type':'text/plain;charset=utf-8'
       // text/plain 纯文本类型
    })
    res.end(JSON.stringify({name:'哈哈哈'}));//{"name":"xxx"} 返回JSON格式的字符串
    
});
server.listen(port);

复制代码

7、关于npm

  • npm -v 查看nom版本号
  • npm install 安装
  • npm init -y 配置项目清单
    • 会自动生成package.json文件
// package.json文件
{
    "name": "NODE",
    "version": "1.0.0",
    "description": "",
    "main": "server.js",
    "scripts": {
        "server": "node server.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
}
复制代码

8、get请求 写接口

<input type="text" id="txt" />

复制代码
txt.onblur = function () {
    jsonp({
        callback:'cb',
        url:"http://localhost",
        data:{
            user:this.value
        },
        success:function(data){
            console.log(data);
        }
    })
}


function jsonp(json) {
    let opt = {
        callback: 'callback',
        url: '',
        data: {},
    }
    let fnName = json.fname || 'jQuery_' + (Date.now());
    window[fnName] = function (data) {
        json.success(data);
        // delete window[fnName];
        window[fnName] = null;
    }

    //动态建立都异步
    let oS = document.createElement('script');
    // oS.src = json.url + '?' +new URLSearchParams(json.data) + '&'+json.callback+'='+fnName;
    json.data[json.callback] = fnName; //cb=jquery_231231
    oS.src = json.url + '?' + new URLSearchParams(json.data);
    document.querySelector('head').appendChild(oS);
    oS.remove();
}

复制代码
// 服务器端

//建立服务器
const http = require('http');
//建立服务
let sql = [
    {
        user: 'Tom',
        password: 123
    },
    {
        user: 'Jess',
        password: 1234
    },
    {
        user: 'Alex',
        password: 12345
    }
];
const app = http.createServer((request, response) => {
    let url = request.url; //接受客户端发送的请求(参数:key=val&key2=val2... 此参数是字符串)
    let obj = {};
    if (url !== '/favicon.ico') {
        // 把url字符串转化为对象 把字符串先转成数组,再把数组转成对象
        url.split('?').split('&').forEach(item => {
            let ary = item.split('=');
            console.log(ary)
            obj[ary[0]] = ary[1];
        });
        // 判断数组中是否有发送来的用户名 
        let isExist = sql.find(e => e.user === obj.user);
        console.log(isExist)
        // 中文设置
        response.setHeader('Content-Type', 'text/html; charset=utf-8');
        // 若是数据数组中有,说明用户名被占用
        // obj.cb 是后台返回给前台的数据
        if (isExist) {
            response.write(obj.cb + "({code:1,msg:'用户名已被注册'})");
        } else {
            response.write(obj.cb + "({code:0,msg:'注册成功'})");
        }
        response.end();
    }
})
//端口监听
app.listen(80)
复制代码

9、post请求 写接口

fetch('/post',{
    body:'user=xiaoqiang',
    method:'post',
    headers:{
        'Content-Type':'application/x-www-form-urlencoded'
    }
    }).then(e=>e.json())
    .then(d=>{
    console.log(d);
});

复制代码
// 服务器端
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
// const 

let sql = ['zhiqiang']
http.createServer((req,res)=>{
    let url = req.url;
    if(url !== '/favicon.ico'){
        //走文件
        if(url.includes('.html')){
            try {
                let d = fs.readFileSync('./www'+url);
                res.write(d.toString());
            } catch (error) {
                let er = fs.readFileSync('./www/404.html');
                res.write(er.toString());
            }
            res.end();
        }else{
            //走接口

            if(url === '/post'){
                let str = '';
                req.on('data',(d)=>{
                    // console.log(d.toString())
                    str += d;
                });

                req.on('end',()=>{
                    // console.log(str.toString(),111);
                    let obj = querystring.parse(str);
                    // console.log(.user)
                    res.setHeader('Content-Type','text/html;charset=utf-8');
                    if(sql.includes(obj.user)){
                        res.write(JSON.stringify({code:0,msg:"失败"}));
                    }else{
                        res.write(JSON.stringify({code:1,msg:"成功"}));
                    }
                    res.end();
                });
            }
        }
    }
    
}).listen(80);



复制代码

====

服务器上有一堆项目代码,这堆项目代码中既可能有服务器端的程序代码,也可能有客户端的程序代码,而客户端的程序代码咱们通常放到static(静态的)这个文件夹当中

static/publice: 都是服务器端须要返回给客户端,有客户端浏览器渲染和解析的(前端项目:包括页面、css、js、图片等)

server.js: 都是须要在服务器端基于node执行的(后端项目:通常只有js)

相关文章
相关标签/搜索