做一道题,理解一下:
function getPrinterList() {
let res = '初始'
setTimeout(() => {
res = 1
},1000)
return res
}
let res = getPrinterList()
console.log(res); //输出'初始'
在getPrinterList函数中,先分清同步异步.
JS执行语句时,会区分同步异步,把所有的同步放在同步队列中,把所有的异步放到异步队列中; 等所有的同步任务执行完,再执行异步任务. 所以输出的res是'初始'.
如果我们想让getPrinterList函数输出为 1, 那么该怎么办呢?
只需将getPrinterList函数返回一个promise即可,代码见下:
function getPrinterList() {
return new Promise((resolve,reject) => {
let res = '初始'
setTimeout(() => {
res = 1
resolve(res)
},1000)
})
}
(1)---getPrinterList().then(res => {console.log(res)}) //输出的res为1
此处和我们经常使用封装好的request请求是一样的.
(2)
关于(1)也可以写为:
async func(){
const res = await getPrinterList()
console.log(res) //输出的res为1
}
注意:resolve(res)抛出结果的位置,是在setTimeout()里面;
function getPrinterList() {
return new Promise((resolve,reject) => {
let res = '初始' //同步
setTimeout(() => { //异步
res = 1
},1000)
resolve(res) //同步
})
}
getPrinterList().then(res => {console.log(res)}) //输出为'初始'
如果resolve(res)放在setTimeout外面,那么输出的res就不是1,而是'初始'了.
可见: 将getPrinterList函数内返回一个Promise,就可以实现我们想要的效果.
类似的,平时我们使用封装好的request,返回的就是promise. 写法有2种:
①先封装好接口函数:
②使用接口函数发送请求:
发送请求写法(1),使用.then
发送请求写法(2),使用async await 语法糖
async getTableData(){
const res = await registrationGetRegistRequestPage(请求参数)
res就是请求的结果
// const res = await registrationGetRegistRequestPage(请求参数).finally(() => {})
//使用await时,也可直接调用finally()即无论请求结果成功与否,都要执行的语句
}
关于Promise, 学习可参考: ES6---promise详解及用法_es6 promise的用法_Cirrod的博客-CSDN博客
Promise是一个容器,是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果.
const service = new Promise((resolve,reject) => {
resolve()可抛出成功结果res即resolve(res); 也可不抛resolve() ----> 抛出成功状态
reject()可抛出失败结果error即reject(error); 也可不抛reject() ----> 抛出成功状态
})
service.then()是promise实例的方法,成功时调用
service.catch()是promise实例的方法,失败时调用
service.finnaly()是promise实例的方法,无论成功失败都会调用
而async await是promise的语法糖, 用来处理promise结果.可代替.then ()
使用 async 定义的函数,当它被调用时,它返回的其实是一个 Promise 对象。(当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。)
需求: 打印报告成功后, 记录打印次数并且刷新列表.代码如下:
原写法:
// 点击打印按钮
async printSingleReport({ row }) {
// 获取pdf文件流
let arrayBuffer = await docReportGainReportPdf({
registrationFormSoid: row.registrationFormSoid,
requestSoid: row.requestSoid,
operatorSoid: row.operatorSoid,
});
let bob = new Blob([arrayBuffer]);
// 文件大小太小说明没有获取的pdf流
if (bob.size < 20) {
this.$message({
message: `报告未出!`,
type: "warning",
});
} else {
this.node2Print(bob, row);
this.recordPrint(row);
}
},
// 记录打印报告次数
async recordPrint(row) {
// 不需要返回
await saveReportPrintRecord({
registrationFormSoid: row.registrationFormSoid,
requestSoid: row.requestSoid,
operatorSoid: row.operatorSoid,
});
},
// blob用于传给node接口打印pdf,row用于后续记录打印次数入参所用
async node2Print(blob, row) {
const formData = new FormData();
formData.append("file", blob);
formData.append("fileType", "pdf");
formData.append(
"printName",
this.$parent.printReportDevice.printDeviceName
);
formData.append("type", "server");
printPDFCustom(formData).then(
(res) => {
if (res.code === 200) {
this.$message.success("打印成功");
}
this.$parent.initTableNeedInfo(); //打印报告成功后,刷新列表
},
(error) => {
console.log(error);
}
);
},
原写法解析: 很有可能会出现一个问题:
现写法: 将打印方法内部返回promise, 再走记录打印次数方法和刷新列表
// 点击打印按钮
async printSingleReport({ row }) {
// 获取pdf文件流
let arrayBuffer = await docReportGainReportPdf({
registrationFormSoid: row.registrationFormSoid,
requestSoid: row.requestSoid,
operatorSoid: row.operatorSoid,
});
let bob = new Blob([arrayBuffer]);
// 文件大小太小说明没有获取的pdf流
if (bob.size < 20) {
this.$message({
message: `报告未出!`,
type: "warning",
});
} else {
this.node2Print(bob).then((res) => {
if (res.code === 200) {
this.$message.success("打印成功");
this.recordPrint(row); //记录打印次数
this.$parent.initTableNeedInfo(); //打印报告成功后,刷新列表
}
});
}
},
// 记录打印报告次数
async recordPrint(row) {
// 不需要返回
await saveReportPrintRecord({
registrationFormSoid: row.registrationFormSoid,
requestSoid: row.requestSoid,
operatorSoid: row.operatorSoid,
});
},
// node打印-返回promise
node2Print(blob) {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.append("file", blob);
formData.append("fileType", "pdf");
formData.append(
"printName",
this.$parent.printReportDevice.printDeviceName
);
formData.append("type", "server");
printPDFCustom(formData).then(
(res) => {
resolve(res);
},
(error) => {
reject(error);
}
);
});
},
现写法解析:打印方法内部返回promise写法 , 拿到结果再做其他操作,这样不会出现异步的情况
如果不用.then 可以使用await
或者node2Print方法内部不用返回promise, 更简单的写法,, 直接以下写法更简单粗暴:
实际使用2:
需求:在父组件触发dispatch请求的数据,存储在vuex中时。子组件需要用到这个数据时,有可能会出现获取不到的问题。
解决思路:在dispatch成功后再触发子组件的方法操作。
先看下全局异步请求,返回的是promise才可以:
从上看到getSelecteds被触发后会返回promise, 那么我们在父组件中dispatch后调用.then方法即可。
JS的执行机制,会区分同步任务和异步任务. 先执行同步任务 再执行异步任务
而异步任务又分为: 宏任务 微任务. (先执行微任务,再执行宏任务)
所以执行顺序可以概括为: 同步任务 微任务 宏任务
常见的同步任务: console; new Promsie; resolve() ; while(true){....} ; fun() 函数调用
常见的宏任务任务: setTimeout; setInterval;
常见的微任务: process.nextTick; promise.then(); 跟在await右边的代码
注意: 先将所有的同步任务 宏任务 微任务分开;
先执行同步任务; 再检查微任务队列是否有任务有则执行; 再执行宏任务.
若有多个宏任务,当当前宏任务中又有微任务,那么将微任务放到微任务队列中. 当执行完该宏任务内的同步任务后,再去执行微任务队列中的微任务.执行完毕之后, 这个循环才算结束. 这个时候再去执行下一个宏任务.
例题1参考: js的执行机制_js执行机制_山上有晚星的博客-CSDN博客
例题2:async、await、promise、setTimeout关于宏任务和微任务_async是宏任务还是微任务_周公子よ的博客-CSDN博客
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log( 'async2');
}
console.log("script start");
setTimeout(function () {
console.log("settimeout");
},0);
async1();
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
console.log('script end');
// script start; async1 start; async2; promise1; script end; async1 end; promise2; settimeout