1. 新老版本对比
| No | 老版本 | 新版本 |
|---|---|---|
| 1. | NodeJs8.9.1 | NodeJs16.13.0 |
| 2. | Mysql2.15.1 | Mysql2.18.1 |
2. 技术变迁
迁移过程中:老版本的代码,在新版本环境中面临以下窘境。
- Callback地狱模式早已不适应新时代发展
- 部分代码完全不能执行。
- 编码方式已发生改变。
3. 在有限资源及有限时间,如何快速升级?
3.1 编码方式:commonJS和Module(ES6方式)
- commonJS:接近老版本方式,风险较低
- Module:需要框架整体变化,风险较大
3.2 callback地狱模式改进
有两种选择
- Promise模式:解套callback,有限修改
- await/async:全盘考虑,重新构建
3.3 下层如果是callback的情况下,怎么修改?
老版本:---test exports.aaaa=function(callback){ ... callback.Success(true); ... callback.Failure(err); } test.aaaa({ Success:testA, Failure:testB }); 新版本:---test exports.aaaa=function(){ return new Promise(function(resolve,reject){ ... resolve(true); ... reject(err); }); } test.aaa().then(v=>{}).catch(reason=>{});
3.4 下层如果是多个的情况下,该如何是好?
新版本:test Promise.all([aaa,bbb]) .then(r=>{}) .catch(reason=>{ });
4. 如果考虑bean进行属性复制,nodejs怎么做呢?
Object.assign(to,from);
5. 找寻几个昼夜,执行突然中断,原因一定要小心?
- A. 不该resolve()的地方,手欠多写了一句
- B. Promise执行方式,通常的写循环的语句可能都失灵了:考虑用递归
- C. 尤其NodeJS写Batch一定要想好启动及结束条件是怎样的。
循环形式如下:
collections.forEach(function(collection){
// 内部逻辑处理(这部分验证过基本是并发执行)
});
如想顺序执行,可修改成如下两种形式:
5.1 顺序执行,async方式
async.eachSeries(
collections,
function(collection,iteratorCallback){
// 内部逻辑处理(这部分验证过基本是顺序执行)
},
function(error){
// 都处理完的逻辑
})
5.2 顺序执行,递归方式
let loopList = (index) => {
if(index > 100){
return;
}else{
loopFunction(index);
index=index+1;
loopList(index);
}
}
loopList(0);
6. 如何像java那样,把相同逻辑共通化,不同逻辑提取出来?
函数作为参数,传递下去,写起来虽然怪怪的;至少可以少写轮子,如下:
定义的地方:
exports.doSomething = function(a,b,doFunction){
const buss = {busses:'doSomething'};
logger.info("process start ",buss);
return new Promise(function (resolve, reject){
doFunction(a,b)
.then(res=>{
resolve();
})
.catch(reason=>{
reject(reason);
});
}).finally(()=>{
logger.info("process end ",logBuss);
});
}
调用的地方:
const some = require('/moduleA');
function doFun1(a,b){
const buss = {busses:'doFun1'};
logger.info("process start ",buss);
return new Promise(function (resolve, reject){
try{
resolve(a+b);
}catch(err){
reject(err);
}
}).finally(()=>{
logger.info("process end ",logBuss);
});
}
some.doSomething(1,2,doFun1);
7. 日志部分
日志输出方向:控制台,文件,AWS CLOUDWATCH
查看详细代码
const winston = require('winston');
require('winston-daily-rotate-file');
const consoleTransport = new winston.transports.Console({
level: 'debug',
silent: false
});
const AWS = require('aws-sdk');
const CloudWatchTransport = require('winston-aws-cloudwatch');
AWS.config.update({
region: process.env.LOG_RIGION_NAME,
});
const fileTransport = new winston.transports.DailyRotateFile({
level: 'info',
silent: false,
handleExceptions: true,
filename: process.env.LOG_INFO_FILE_NAME,
datePattern: 'MM-DD'
});
const errorTransport = new winston.transports.DailyRotateFile({
level: 'error',
name: 'error-file',
handleExceptions: true,
filename: process.env.LOG_ERROR_FILE_NAME,
datePattern: 'MM-DD'
});
const cloudWatchTransport = new CloudWatchTransport ({
logGroupName: process.env.LOG_GROUP_NAME,//REQUIRED
logStreamName: process.env.LOG_STREAM_NAME,//REQUIRED
createLogGroup: true,
createLogStream: true,
submissionInterval: 2000,
submissionRetryCount: 1,
batchSize: 20,
awsConfig: {
accessKeyId: '',
secretAccessKey: '',
region: process.env.LOG_RIGION_NAME
},
formatLog:item => {
let meta = item._meta;
let message = item._message;
let level = 'item';
if(item.level.includes('debug')){
level = 'debug';
}
if(item.level.includes('warn')){
level = 'warn';
}
if(item.level.includes('error')){
level = 'error';
}
if(meta.metadata !=undefined && meta.metadata != null){
let out = ``;
Object.keys(meta.metadata).forEach(function (key){
out += `[` + meta.metadata[key] + `]`;
});
return `[${meta.label}]` + out + `${level}:${message}`;
}else{
return `[${meta.label}]${level}:${message}`;
}
}
});
let logger = winston.createLogger({
level: 'info',
exitOnError: false,
format: winston.format.combine(
winston.format.label({ label: 'test' }),
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
winston.format.colorize(),
winston.format.splat(),
winston.format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }),
winston.format.printf((item) => {
let out = ``;
if (Object.keys(item.metadata).length > 0) {
Object.keys(item.metadata).forEach(function (key){
out += `[` + item.metadata[key] + `]`;
});
return `${item.timestamp}[${item.label}]` + out + `${item.level}:${item.message}`;
} else {
return `${item.timestamp}[${item.label}]${item.level}:${item.message}`;
}
}),
),
transports: [consoleTransport,fileTransport,errorTransport,cloudWatchTransport]
});
module.exports = logger;
8. 数组操作
在操作DB时,为了安全起见通常采用?的方式来作为参数占位符。这个时候,就会有一个问题,如何给参数赋值:
- 一般做法,往参数数据推送数据,例如:
let arr=[];
arr.push(arr);
- 遇到多个参数时,有时也会合并数据,例如:
let arr=[1,2];
let val=[3,4,5];
Array.prototype.push.apply(arr,val);
9. 多进程合并执行
nodejs中,使用package.json中scripts片段,很方便。
单功能A,如下:
"scripts": {
"start-A:dev": "node -r dotenv/config ./app A dotenv_config_path=./config/.env.dev ",
}
单功能B,如下:
"scripts": {
"start-B:dev": "node -r dotenv/config ./app B dotenv_config_path=./config/.env.dev ",
}
上面两个功能单独执行,没有任何问题。
9.1 但如果想让功能A和功能B一起执行的话,该如何处理?
针对这种问题,nodejs给出了两种解决方案:
- 顺序执行,使用 && 来连接,代码如下:
"start:dev": "npm run start-A:dev && npm run start-B:dev",
- 并发执行,使用 & 来连接,代码如下:
"start:dev": "npm run start-A:dev & npm run start-B:dev",
注意:并发执行时,如果打日志会很混乱。
9.2 如果在连接好的命令前后加些处理,又该如何?
nodejs也给出了解决方案,pre命令---post命令,如下:
"prestart:dev": "npm run commandPre",
"start:dev": "npm run start-A:dev & npm run start-B:dev",
"poststart:dev": "npm run commandPost",
10. vue3 element ui
10.1 el-dialog每启动一次z-index累加
- Q:导致z-index的值超过对话框面板上的组件的z-index,弹不出来。
- A:这是版本"element-plus": "1.3.0-beta.3"所致,在"element-plus": "1.3.0-beta.5"已修改。
11. el-upload 缓存清除
- Q:上传大的视频,采取断点续传结束时,文件列表会残留(如何清除残留成了课题)
- A:vue3中的清除办法如下
# 定义
const { proxy } = getCurrentInstance();
# 使用
proxy.$refs.upload.clearFiles();
12. 上传文件,附带加参数如何设置
后台:
@PostMapping
@ResponseBody
public AjaxResult test(@RequestPart("file") MultipartFile file,@RequestParam("isNeed") Boolean isNeed){
}
Postman设置
Body
- file file
- isNeed boolean false
13. el-input回车刷新画面问题
一般发生此问题,都是有form表单,可以进行组织处理 修改前
<el-form :model="queryParams" >
<el-form-item label="タイトル" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入抬头"
clearable
size="small"
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-form
修改后
<el-form :model="queryParams" @submit.native.prevent>
<el-form-item label="タイトル" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入抬头"
clearable
size="small"
style="width: 240px"
@keyup.enter="handleQuery"
/>
</el-form-item>
</el-form
14. 兄弟组件间,如何信息传递?
VUE3中可以使用mitt
bus.js
import mitt from 'mitt'
const bus = mitt();
export default bus;
兄弟组件1
import bus from '@/utils/bus
bus.emit('listenWebsocket',{source: source});
兄弟组件2
import bus from '@/utils/bus'
bus.on('listenWebsocket',data=>{
if(data.source == 'app'){
getList();
}
})
# 组件退出之前,关掉此listenWebsocket
onBeforeUnmount(()=>{
bus.off('listenWebsocket')
})