用了es6这么久,一直没用过async,只在书上看过,也没实践过,总是忘。
现在记录一下笔记,其实Async应该是es7的内容。
从Promise开始,Js异步编程的关键就是Promise了。
直接上代码,该编译环境是 Node v8+ ,如果低于可能需要babel来转译。
下面定义了两个函数,由于Promise一旦被创建立即执行,因此,用函数来控制,Promise有两种状态,一种 Resolve,一种是Reject,即成功与失败。Promise接受一个参数类型为:function。
下图很明显:(resolve,reject)=>{}这个就是我们传给Promise的参数,其中resolve与reject是回调函数,由js引擎提供,黑盒操作。我们可以在Promise的函数内部,调用这两个回调函数,注意:调用其一,Promise状态立刻改变,不可回退、比如,我们经常会使用ajax请求,当success时候,我们就调用Reslove函数告诉Promise改变状态为成功,如果ajax调用失败,我们可以调用reject告诉Promise状态改为失败,如下所见,这两个回调接受参数,我们可以通过一系列的异步任务,依次调用,处于后面的异步可以接受上层的返回数据。
当然,我们也快可以返回新的Promise,实现连续异步的调用。,如p1与p2的返回。
一旦我们调用resolve函数,Promise就停止工作。我们可以使用then函数来获取接下来的工作,比如接收返回值,或者,这里可以明确知道,异步任务已经执行完毕,在这里执行下一个异步任务。
then():该函数接收两个参数,第一个是Promise Resolve状态调用,第二个是reject状态调用。
我们可以看到,在p1().then(e=>console.log(e))只用了一个参数,因为对于reject我们使用另个catch函数来捕获错误。
如果不用catch,需要 p1().then(e=>xx,error=>xx)
这里有一个注意点:如果Promise一旦变为Resolve状态,catch将无法捕获错误。
比如,下面p2返回了一个新的Promise,该任务,我们手动执行了reject,该Promise变为reject状态,返回一个错误到上层p2,如果我们不在p2后面捕获catch,该错误会冒泡上层,如果在第一个p1后面捕获,将不会获取到,因为,p1此时已经是resolve了。
let p1 = () => {
return new Promise((resolve, reject) => {
console.log('3秒钟后,p1函数结束');
setTimeout(() => {
//返回Promise
resolve(p2())
}, 3000)
})
};
let p2 = () => {
return new Promise((resolve,reject)=> {
console.log('p1结束,现在是第二个任务了!');
resolve({key: 2, content: "第二个任务结束"})
}
)
};
p1().then((res) => {
console.log(res);
p2().then((res2) => {
console.log(res2);
//返回Promise
return new Promise((resolve ,reject)=> {
console.log('开始第三个任务,这个任务是继续第二个的异步。');
setTimeout(()=>reject({key:3,content:"第三个任务报错!"}),2000)
})
}).catch((error)=>console.log(error));
});
//在resolve后调用catch无效,无法抛出错误,因为状态已经改变
下面是Promise的两个包装函数。
还是代码,因为比较直观。
下图是包装的多个Promise。通过Promise.all()方法,将一系列的Promise实例合成一个Promise,该Promise状态受到子Promise的影响,当所有的子Promise都变为Resolve,外层Promise变为Resolve状态,并将子Promise的返回值按照数组返回。一旦有一个子promise变为reject,promise变为Reject,返回第一个报错,停止。
//多个异步操作包装
let p4 = ()=>{
return new Promise((resolve)=>{
resolve('p4 over')
})
};
let p5 = ()=>{
return new Promise((resolve)=>{
resolve('p5 over')
})
};
Promise.all([p4(),p5()]).then((e)=>console.log(e)).catch((e3)=>console.log('error:'+e3));
下面是Promise.race(),字面意思就是看谁最先执行了。
和all不同的是,这个方法返回最先改变状态的子Promise返回值。
//Promise.race 返回最先改变状态的Promise的值
let p6 = ()=>{
return new Promise((resolve)=>{
console.log('p6 go');
setTimeout(()=> resolve('p6 over'),4000)
})
};
let p7 = ()=>{
return new Promise((resolve)=>{
console.log('p7 go');
setTimeout(()=> resolve('p7 over'),2000)
})
};
Promise.race([p6(),p7()]).then((e)=>console.log(e)).catch((ee)=>console.log(ee));
输出:
最后是Asycn了。
Async就是对Promise的语法糖了,当然此处略过(generate....等)
定义与实例:下面并没有使用Promise,一会再用,先看看一般情况下,Async的使用。
//Async
let a0 = ()=>{
console.log('等待a0执行...');
setTimeout(()=>{
console.log('a0 over')
},2000)
};
let a00 = ()=>{
console.log('等待a00执行...');
setTimeout(()=>{
console.log('a00 over')
},3000)
};
let as1 = async ()=>{
await a00();
console.log('执行a00');
await a0()
};
as1().then();
首先定义多个 Async关键字。
其次有个await关键字,这个关键字:等待 后面的执行,一般是Promise或耗时任务,一会第二个例子就是用法。
看看与Promise的配合。
下面的例子,定义了一个async函数,并且自动执行,我们看到输出结果,就一目了然了。
let a3 = ()=>{
return new Promise((resolve)=>{
setTimeout(()=>resolve('a3 over'),4000)
})
};
let a4 = ()=>{
return new Promise((resolve)=>
setTimeout(()=>resolve('a4 over'),1000))
};
(async function async2() {
console.log('开始序列执行a3,a4');
let res3 = await a3();
console.log(res3);
let res4 = await a4();
console.log(res4);
})();
输出:即使a3是最慢的,但是还是等它执行完,再执行a4的,如果使用Promise,需要一堆嵌套与then来处理。