Js中的异步操作:
众所周知,javascript是一种单线程语言,实现起来比较简单,但是只要有一个任务正在执行,那其他任务只能等待这个任务执行完成才能继续,严重影响执行效率,为了解决这种问题,js创建了异步执行模式。
回调函数:
回调函数是实现异步模式的最基础的实现方法,以setTimeout为例,将f2函数作为参数传入f1函数中(传入的是函数名f2,而不是f2()),推迟f2的执行,就不会堵塞后续任务的执行。
function f1(callback) {setTimeout(function(){callback()},10000)};
f1(f2);
Promise对象
Promise 是异步编程的一种解决方案,相对于回调函数而言,能够监测异步函数的执行状态,更合理且更强大。Promise主要有三种状态:pending,fulfilled,rejected,分别对应进行中,成功和失败。
Promise创建:
Promise构造函数中主要有两个参数:resolve和reject,分别是异步操作成功和异步操作失败后调用的函数,这两个函数都会将结果传递出去,在对象创建完成之后,就可以通过.then和.catch分别传入对应的处理函数。
var promise = new Promise(function(resolve, reject){
if (/* 异步操作成功 */) {resolve(value);}
else { reject(error);}
})
promise.then((value)=>{console.log(value)})//作为resolve回调函数传入
.catch((error)=>{console.log(error)})//作为reject回调函数传入
执行顺序:
let promise = new Promise(function(resolve, reject){console.log("AAA");resolve()});
promise.then(() => console.log("BBB"));
console.log("CCC")
执行输出为AAA=>CCC=>BBB,表明Promise在新建后会立即执行,所以首先输出 AAA。然后,then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行,所以BBB 最后输出。
一般axios的请求都会以promise的形式传递给前端参数,然后使用.then()进行相应的处理,而我们在.then之外是得不到结果的,因为异步执行会将当前的同步任务执行完成后才会执行。页面上可以显示是因为渲染watcher的作用,包括watch和computed也是这个道理。
链式结构:
then()方法会返回一个新的Promise实例,所以then()方法后面可以继续跟另一个then()方法进行链式调用。前一个then如果有返回值,该返回值将继续作为参数传入到下一个then。
promise.then((res) => {console.log(res);return res;})
.then((val)=>{console.log(val)})
async/await:
async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成,并且await 只能出现在 async 函数中(后面会解释)。
async:
async 函数会返回一个 Promise 对象。如果返回值不是一个promise对象,async也会强制封装成 Promise 对象,然后再返回。由于返回的是promise对象,那后面就可以通过then方法来处理。
async function test() {
return "123";
}
console.log(test()) //输出 Promise {<fulfilled>: '123'}
test().then(v => {console.log(v); // 输出 123});
await:
正常情况下,await命令后面是一个Promise对象,会等待返回该对象的结果。如果后面跟着的不是promise对象,await也会进行等待,等待的后果就是会阻塞后面任务的执行,所以await就只能用在async函数中,相对于链式处理,await的优势在于更加简洁方便。借边城老师的例子一用:
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
return takeLongTime(n);
}
function step2(m, n) {
return takeLongTime(m + n);
}
function step3(k, m, n) {
return takeLongTime(k + m + n);
}
如果使用链式来调用,中间还会涉及到promise对象嵌套:
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => {
return step2(time1, time2)
.then(time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
return step3(time1, time2, time3);
})
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
如果使用async/await,一下子就简洁好多,舒服~
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();