龙空技术网

node学习笔记(四十二)

陆荣涛 68

前言:

而今小伙伴们对“nodejs json对象”大致比较关心,各位老铁们都想要了解一些“nodejs json对象”的相关资讯。那么小编也在网摘上汇集了一些有关“nodejs json对象””的相关资讯,希望姐妹们能喜欢,同学们快快来学习一下吧!

一、前端EventLoop

1、什么是eventLoop?

同步任务和异步任务在js中是如何执行的呢?js的代码运行会形成一个主线程和一个任务队列。主线程会从上到下一步步执行我们的js代码,形成一个执行栈。同步任务就会被放到这个执行栈中依次执行。而异步任务被放入到任务队列中执行,执行完就会在任务队列中打一个标记,形成一个对应的事件。当执行栈中的任务全部运行完毕,js会去提取并执行任务队列中的事件。这个过程是循环进行的,这就是我们今天想要了解的event loop

2、为什么js是单线程

想要了解event loop我们就要从js的工作原理说起。首先,大家都知道js是单线程的。所谓单线程就是进程中只有一个线程在运行。那么,js为什么是单线程而不是做成多线程的呢?个人理解,js是用来实现浏览器与用户之间的交互的。如果同时要处理用户点击,用户输入,用户关闭等操作,浏览器无法知道这个时间我到底应该做什么。所以js是从上至下按顺序运行下去的

3、什么是宏任务&&什么是微任务

宏任务: 需要多次事件循环才能执行完,事件队列中的每一个事件都是一个宏任务。浏览器为了能够使得js内部宏任务与DOM任务有序的执行,会在一个宏任务执行结束后,在下一个宏执行开始前,对页面进行重新渲染 (task->渲染->task->…)鼠标点击会触发一个事件回调,需要执行一个宏任务,然后解析HTML

微任务: 微任务是一次性执行完的。微任务通常来说是需要在当前task执行结束后立即执行的任务,例如对一些动作做出反馈或者异步执行任务又不需要分配一个新的task,这样便可以提高一些性能

4、案例

console.log("script start");•setTimeout(function(){   console.log("setTimeout");},0)•newPromise(resolve=>{   console.log("promise start");   resolve();}).then(function(){   console.log("promise1");}).then(()=>{   console.log("promise2");})•console.log("script end");console.log(1);•setTimeout(()=>{ console.log(2);})•newPromise((resolve)=>{ console.log(4) resolve()}).then(()=>{setTimeout(()=>{     console.log(5);  })}).then(()=>{ console.log(6)})•console.log(7)setTimeout(() => { console.log(5)• new Promise(resolve => {    console.log(6)•    setTimeout(() => {      console.log(7)    })    resolve()  }).then(() => {    console.log(8)  })}, 500)new Promise(resolve => { console.log(9) resolve()}).then(() => { console.log(10)• setTimeout(() => {    console.log(11)  }, 0)})•console.log(12)

二、后端EventLoop

1、NodeJS中的宏任务分类

Timers 类型的宏任务队列

setTimeout()setInterval

Check 类型的宏任务队列

setImmediate()

Close callback 类型的宏任务队列

socket.on(‘close’, () => {})

Poll 类型的宏任务队列

除了上面几种的其他所有回调

2、nodeJs 里面的微任务队列

process.nextTick()Promise.then() process.nextTick()的优先级高于所有的微任务,每一次清空微任务列表的时候,都是先执行process.nextTick()

3、setTimeout && setImmediate执行顺序

Node 并不能保证 timers 在预设时间到了就会立即执行,因为 Node 对 timers 的过期检查不一定靠谱,它会受机器上其它运行程序影响,或者那个时间点主线程不空闲

虽然 setTimeout 延时为 0,但是一般情况 Node 把 0 会设置为 1ms,所以,当 Node 准备 event loop 的时间大于 1ms 时,进入 timers 阶段时,setTimeout 已经到期,则会先执行 setTimeout;反之,若进入 timers 阶段用时小于 1ms,setTimeout 尚未到期,则会错过 timers 阶段,先进入 check 阶段,而先执行 setImmediate

三、postman的基本使用

1、打开postman之后,首先输入URL,方法选择GET

2、然后我们在Headers里面输入我们所需要的内容,如果需要Cookie也填写在这里面即可(不需要可以不填),填写的时候可以单个填写,也可以点击【Bulk Edit】进行填写方式切换,切换后可以一次填写所有内容

3、填写了Headers之后,如果这个get请求里面有传参,我们接下来可以填写参数,如果不需要也可以不填。填了参数之后,内容就会拼接在我们的url里面

4、最后,我们点击send,就可以看到返回值了

post同理

四、项目的基本搭建一、express生成器搭建项目结构

1、安装 express-generator

npm install express-generator -g

2、通过express -e生成项目结构

3、安装依赖

$ cd myapp

$ npm install

4、启动项目

npm start

二、MVC架构思想

MVC即Model-View-Controller(模型-视图-控制器)是一种软件设计模式,最早出现在Smalltalk语言中,后被Sun公司推荐为Java EE平台的设计模式。

  MVC把应用程序分成了上面3个核心模块,这3个模块又可被称为业务层-视图层-控制层。顾名思义,它们三者在应用程序中的主要作用如下:

业务层:负责实现应用程序的业务逻辑,封装有各种对数据的处理方法。它不关心它会如何被视图层显示或被控制器调用,它只接受数据并处理,然后返回一个结果。

视图层:负责应用程序对用户的显示,它从用户那里获取输入数据并通过控制层传给业务层处理,然后再通过控制层获取业务层返回的结果并显示给用户。

控制层:负责控制应用程序的流程,它接收从视图层传过来的数据,然后选择业务层中的某个业务来处理,接收业务层返回的结果并选择视图层中的某个视图来显示结果。

  可以用下图来表示MVC模式中三者之间的关系:

三、图片上传安装multer模块

npm install multer
引用模块 它是依赖于express的一个模块
//引用express并配置var express = require("express");var app = express();app.listen(3000);var multer = require('multer');/*var upload = multer({    //如果用这种方法上传,要手动添加文明名后缀        //如果用下面配置的代码,则可以省略这一句    dest: 'uploads/'})*/
配置 设置保存文件的地方,并根据上传的文件名对应文件添加后缀 可以通过filename属性定制文件保存的格式

属性值用途destination设置资源的保存路径。注意,如果没有这个配置项,默认会保存在/tmp/uploads下。此外,路径需要自己创建filename设置资源保存在本地的文件名

var storage = multer.diskStorage({    //设置上传后文件路径,uploads文件夹会自动创建。    destination: function(req, file, cb) {        cb(null, './uploads')    },    //给上传文件重命名,获取添加后缀名    filename: function(req, file, cb) {        var fileFormat = (file.originalname).split(".");        //给图片加上时间戳格式防止重名名        //比如把 abc.jpg图片切割为数组[abc,jpg],然后用数组长度-1来获取后缀名        cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);    }});var upload = multer({    storage: storage});
接受文件 upload.single('xxx'),xxx与表单中的name属性的值对应 这里虽然用到post请求,但实际上不需要bodyParser模块处理
app.post('/upload-single', upload.single('logo'), function(req, res, next) {    console.log(req.file)    console.log('文件类型:%s', req.file.mimetype);    console.log('原始文件名:%s', req.file.originalname);    console.log((req.file.originalname).split("."))    console.log('文件大小:%s', req.file.size);    console.log('文件保存路径:%s', req.file.path);    res.send({        ret_code: '0'    });});
多图上传 多图上传只要更改一下地方,前端往file输入框加多一个multiple="multiple"属性值,此时就可以在选图的时候多选了,当然也可以并列多个file输入框(不推荐多个上传图片输入框),这样体验会不好
<input type="file" name="logo" multiple="multiple" />

后端也需要相应的改变

app.post('/upload-single', upload.single('logo'), function(req, res, next) {//upload.single('logo')变为upload.array('logo', 2),数字代表可以接受多少张图片app.post('/upload-single', upload.array('logo', 2), function(req, res, next) {

如果不想有图片数量上传限制,我们可以用upload.any()方法

app.post('/upload-single', upload.any(), function(req, res, next) {     res.append("Access-Control-Allow-Origin","*");    res.send({        wscats_code: '0'    });});
前端部分formData表单提交
<form action="; method="post" enctype="multipart/form-data">    <h2>单图上传</h2>    <input type="file" name="logo">    <input type="submit" value="提交"></form>
formData表单+ajax提交
<form id="uploadForm">    <p>指定文件名: <input type="text" name="filename" value="" /></p>    <p>上传文件: <input type="file" name="logo" /></ p>    <input type="button" value="上传" onclick="doUpload()" /></form>

FormData对象,是可以使用一系列的键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个"表单"

注意点

processData设置为false。因为data值是FormData对象,不需要对数据做处理。<form>标签添加enctype="multipart/form-data"属性。cache设置为false,上传文件不需要缓存。contentType设置为false。因为是由<form>表单构造的FormData对象,且已经声明了属性enctype="multipart/form-data",所以这里设置为false

上传后,服务器端代码需要使用从查询参数名为logo获取文件输入流对象,因为<input>中声明的是name="logo"

function doUpload() {    $.ajax({        url: ';,        type: 'POST',        cache: false, //不必须        data: new FormData($('#uploadForm')[0]),        processData: false,//必须        contentType: false,//必须        success: function(data) {            console.log(data)        }    })}

四、编写接口

api接口

RestfulApi 规范接口文档的生成(apidoc)接口请求方式区别

跨域解决

corsjsonpproxy

五、JWTJWT用户登录 服务器端产生一个token (加密字符串) 发送给前端前端将token 进行保存前端发起数据请求的时候携带token服务端 验证token 是否合法 如果合法继续操作 不合法终止操作token 的使用场景 无状态请求 保持用户的登录状态 第三方登录(token+auth2.0)

非对称加密 通过私钥产生token 通过公钥解密token

// 1.产生公钥和私钥// 产生私钥  openssl genrsa -out ./private_key.pem 1024    1024 代表私钥长度// 产生公钥  openssl rsa -in ./private_key.pem -pubout -out ./public_key.pem let private_key=fs.readFileSync(path.join(__dirname,'./private_key.pem')) let public_key=fs.readFileSync(path.join(__dirname,'./public_key.pem')) var token = jwt.sign(palyload, private_key,{ algorithm: 'RS256'}); console.log(token) let  token='eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IueUqOaIt2lkIiwiaWF0IjoxNTUxMTUyNzk1fQ.TI_xDBvObHGAH7EV40WWpQemm5nx077Gdjq-pzDx0NWN5YFd40S7XcLmgoDdYscLM7vMOP0c7z1l83JUixqk7IBjBCU-tMNo_G5_-LGkQjV3vDYq_3TkXTl42lgmFA-EBey7W6W1PgPfYlowyHAyp-07hXaMRevgVkXm2lPEFXo'​  var decoded = jwt.verify(token, public_key);

const jwt=require('jsonwebtoken')const scrict='sdjfksdjflajflasjflasjflksf'​function creatToken(palyload){    // 产生token    palyload.ctime=Date.now()    return jwt.sign(palyload,scrict)}function checkToken(token){    return  new Promise((resovle,reject)=>{        jwt.verify(token,scrict,(err,data)=>{           if(err){ reject('token 验证失败')}           resovle(data)           })    })    }module.exports={    creatToken,checkToken}

Cookie+Session

const  cookieParse=require('cookie-parser')const  session = require('express-session')​app.use(session({    secret: 'hubwizApp', //为了安全性的考虑设置secret属性    cookie: {maxAge: 60 * 1000 * 60 * 24 }, //设置过期时间    resave: true, // 即使 session 没有被修改,也保存 session 值,默认为 true    saveUninitialized: false, //无论有没有session cookie,每次请求都设置个session cookie ,默认给个标示为 connect.sid}));​

登录成功

req.session.sign = true;req.session.name = us;

需要验证的接口判断是否存在

注销session

app.get('/out', function(req, res){    req.session.destroy();    res.redirect('/');})
六、登录验证码
const svgCaptcha = require('svg-captcha');​生成验证码 返回图片格式async generateVerifCode() {    const codeConfig = {      size: 4, // 验证码长度      ignoreChars: '0oO1ilI', // 验证码字符中排除 0oO1ilI      noise: 2, // 干扰线条的数量      width: 160,      height: 50,      fontSize: 50,      color: true, // 验证码的字符是否有颜色,默认没有,如果设定了背景,则默认有      background: '#eee',    };    const captcha = svgCaptcha.create(codeConfig);    this.ctx.session.verifCode = captcha.text.toLowerCase(); // 存session用于验证接口获取文字码    this.ctx.body = captcha.data;  }

标签: #nodejs json对象 #js node对象 #nodejs 获取输入 #nodejs后端渲染 #nodejs能干什么