一、初始await与async
初学到async与await时只是停留在表面,明白await是用来等待函数执行的,async是用来声明函数为异步函数的,并且只知道只有声明了async的函数,里面才可以用await。
现在想起来,其实也没错,这两个的确是成对出现的。
语法就是:
如果没有声明async将会报错:
二、async有什么作用
1.先来看看例子:
例子1:
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);
c:\var\test> node --harmony_async_await .
Promise { ‘hello async‘ }
打印出来发现,申明了异步的函数,并不是直接返回一个我们想要的值,而是一个promise对象,如果返回的是promise对象,那么就可以使用then链语法,一直then下去:
例子2:
先来看看第一个普通使用promise的例子:
function conductStr(str){
return new Promise((resolve)=>{
resolve(str.substr(5).split(‘>‘))
})
}
//下面代码都是废话,主要看上面绿色区域
let my_str = conductStr(‘当前位置:初三网 >肇庆中考 > 肇庆地区高中>肇庆市第四中学‘)
my_str.then((response)=>{
console.log(response)
}).catch(err=>{
console.log(err)
})
再来看看处理同一操作的async可以怎么写:
async function conductStr(str){
return ( str.substr(5).split(‘>‘))
}
//同样下面是废话
let my_str = conductStr(‘当前位置:初三网 >肇庆中考 > 肇庆地区高中>肇庆市第四中学‘)
my_str.then((response)=>{
console.log(response)
}).catch(err=>{ console.log(err) })
同样输出结果:
我们可以看到,async申明的函数会把返回结果直接实例化一个new promise,然后通过resolve把参数传出去。
所以总结一下:申明异步函数的返回值会默认返回一个promise,这个返回值可以使用then链语法,一直写下去。
三、await有什么作用
await是用来等待后面的表达式执行完毕,才能继续执行下去,await后面的表达式可以是一个函数,也可以是一个普通表达式子
看看例子:
(1)异步方法1,2都用了await的情况:
function Async1() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法1");
}, 1000);
})
}
function Async2() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法二");
}, 10);
})
}
async function test() {
const v1 = await Async1();
const v2 = await Async2();
console.log(v1, v2);
}
test();
可以看到直接输出resolve的参数
(2)异步方法1不用await,异步方法2用await
function Async1() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法1");
}, 1000);
})
}
function Async2() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法二");
}, 10);
})
}
async function test() {
const v1 = Async1();
const v2 = await Async2();
console.log(v1, v2);
}
test();
可以看到没有await,直接返回一个pending,那么是否await来等待一个具体值呢?这个我们等下再考虑。
(3)await是否可以等待其它函数,或者表达式:
function normal(){
let a=1;
return"我是同步函数"
}
async function Async0(){
return"我是异步函数零"
}
function Async1() {
return new Promise((resolve)=>{
setTimeout(() => {
resolve("我是异步方法一")
}, 1000);
})
}
function Async2() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法二");
}, 10);
})
}
async function test() {
const num = await (1+1);
const n = await normal()
const v0 = await Async0();
const v1 = await Async1();
const v2 = await Async2();
console.log(n,v0,v1, v2,num);
}
test();
问题答案如上面演示,答案还可以的。
(4)同步方法没有返回值时,await会怎么处理
function normal(){
let a=1;
}
function Async1() {
return new Promise((resolve)=>{
setTimeout(() => {
resolve("我是异步方法一")
}, 1000);
})
}
function Async2() {
return new Promise((resolve)=>{
setTimeout(() => {
return resolve("我是异步方法二");
}, 10);
})
}
async function test() {
const n = await normal()
const v1 = await Async1();
const v2 = await Async2();
console.log(n,v1,v2)
}
当同步没有返回值时,await默认返回undefined,因为await会任务同步函数执行完了,然后await知道同步函数没有返回值。
(5)异步方法没有返回值时,await怎么操作
function normal(){
let a=1;
}
function Async1() {
return new Promise((resolve)=>{
setTimeout(() => {
resolve("我是异步方法一")
}, 1000);
})
}
function Async2() {
return new Promise((resolve)=>{
setTimeout(() => {
// return resolve("我是异步方法二");把异步方法二返回值注释掉
}, 10);
})
}
async function test() {
const n = await normal()
const v1 = await Async1();
const v2 = await Async2();
console.log(n,v1,v2)
}
test();
此时await会直接退出,其实我觉得应该结果会直接阻塞才对,因为异步代码没有返回值,await就会一直等待,await一直等待,test异步函数就会奔溃,最后退出才对;因为await可以判断同步代码没有返回值,但是异步代码返回值什么时候返回它是无法知道的。
说明白一点,我们知道通常我们使用promise是用来包着一个异步操作的,等待异步操作完成,才把结果resolve出去,但是这个异步操作什么时候完成,没有人会知道,就像我们在像网络世界发起请求时,如果服务器响应速度快,我们就很快得到数据,相反,要是服务器很慢,我们就很晚才拿到数据。
回到上面那个例子,settimeout就是一个异步操作,里面resolve就是包含着我们的数据,如果我们一直不resolve,外面就一直拿不到数据,所以我自己觉得要是await在超出一段时间拿不到数据,它就认为请求失败,整个async函数全部退出,即使最前面的几个await拿到值了,它也会导致程序直接退出。
四、总结
(1)async用来申明一个函数是异步函数,只有申明了async的函数,内部才可以使用await;
(2)await是用来等待一个表达式的,这个表达式可以是任何一个表达式,当返回的为非promise表达式时,无论await等到的是什么,都不影响整个异步函数,当等到的是promise,而这个promise没有返回值时,它就会导致整个异步函数退出。(就像promise的中文意思一样,承诺,就是它承诺了会返回一个数据,但是结果它没有返回,如此不诚信的行为将会导致整个函数退出)
五、给出await与async在实际应用中的例子:
单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了(很有意思,Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它)。
假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout
来模拟异步操作
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
现在用 Promise 方式来实现这三个步骤的处理
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1507.251ms
输出结果 result
是 step3()
的参数 700 + 200
= 900
。doIt()
顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500
毫秒,和 console.time()/console.timeEnd()
计算的结果一致。
如果用 async/await 来实现呢,会是这样:
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样
现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
这回先用 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();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 800 = 300 + 500
// step3 with 1800 = 300 + 500 + 1000
// result is 2000
// doIt: 2907.387ms
除了觉得执行时间变长了之外,似乎和之前的示例没啥区别啊!别急,认真想想如果把它写成 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");
});
}
doIt();
参考文章:https://segmentfault.com/a/1190000007535316
Javascript中的await与async与promise存在什么关系?
原文:https://www.cnblogs.com/hmy-666/p/14528296.html