综合技术

JS笔记(21): NODE

微信扫一扫,分享到朋友圈

JS笔记(21): NODE
0

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

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

2) NODE安装完之后

npm(node Package Managernode模块管理器)
node xxx.js

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

  • REPL模式: Read-Evaluate-Print-Loop
    输入-求值-输出-循环
  • 直接基于node来执行JS文件

    • 在命令窗口中执行(DOS窗口 & 终端窗口)

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

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

4) NODE的优势和特点:

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

  • 单线程
  • 基于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安装使用
  • 自定义模块:自己创建的一些模块

二、CommonJS规范

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

  • CommonJS规定,每一个js都是一个单独的模块(模块是私有的:里面涉及的值和变量以及函数都是私有的,和其他js文件中的内容是不冲突的)
  • CommonJS中可以允许模块中的方法互相的调用

    • B模块中想要调取A模块中的方法
    • => A导出
    • => B导入

1) 导出

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

  • 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

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

  • require('./xxx')

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

5) CommonJS的特点:

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

三、内置变量__dirname & __filename

  • __dirname
    : 模块中这个内置变量是当前模块所在的绝对路径(具体到盘符:物理路径)

    console.log(__dirname)
    C:UserslenovoDesktopnotesNODE
    
  • __filename
    : 相对于_dirname来讲,多了模块名称 (即对了文件名称)

    • C:UserslenovoDesktopnotesNODEabout_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:UserslenovoDesktopnotesNODE
console.log(__filename) //C:UserslenovoDesktopnotesNODEabout_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
复制代码

四、fs内置模块

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

常用方法:

  • fs.mkdir / fs.mkdirSync
    :创建文件夹
    有Sync的是同步创建,反之是异步,想要实现无阻塞I/O操作,我们一般用异步完成 fs.mkdir(path,callback)
    f
    s.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:UserslenovoDesktopnotesNODEmodule_fsless']
*/

// 读取文件内容
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')
})
复制代码

五、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对象
复制代码

六、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);

复制代码

七、关于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"
}
复制代码

八、

<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)
复制代码

阅读原文...


稀土掘金

游戏拼命“挤”进高校,图的不仅是人闲钱多?

上一篇

最佳游戏花落谁家?E3 2019 IGN大奖提名出炉

下一篇

您也可能喜欢

评论已经被关闭。

插入图片
JS笔记(21): NODE

长按储存图像,分享给朋友