首页 > 编程语言 > 详细

Javascript中的await与async与promise存在什么关系?

时间:2021-03-13 15:41:55      阅读:34      评论:0      收藏:0      [点我收藏+]

一、初始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在实际应用中的例子:

1. async/await 的优势在于处理 then 链

单一的 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 = 900doIt() 顺序执行了三个步骤,一共用了 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 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样

2. 还有更酷的

现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。

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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!