es6的async和await

  1. async

(1) async关键字用于申明异步函数,可用于箭头函数,函数表达式,function函数声明,方法

const fun = async () => {
  console.log(1)
}
async function fun1() {
  console.log(2)
}
const o = {
  say: async () => {
    console.log('say')
  }
}

(2) 使用async关键字声明的函数具有异步特征(返回的是一个Promise实例对象,函数内部可以使用await关键字),但总体上其代码还是同步求值的,即函数调用是同步任务

const fun = async () => {
  console.log(1)
}
console.log('fun',fun())
console.log(2)
打印结果:
1
fun() Promise { undefined }
2

(3) 异步函数如果使用return关键字返回了值,那么这个值会被Promise.resolve包裹成一个期约对象(即Promise实例对象)

const f = async () => {
  return 100
}
console.log(f())
f().then(console.log)
打印结果:
Promise {100}
100

(4) 也可以直接返回一个期约对象

const f1 = async () => {
  // return Promise.resolve('这是一个Promise实例对象')
  return Promise.reject('这是一个Promise实例对象')
}
f1().catch(console.log) // 这是一个Promise实例对象

(5) 还可以返回一个实现thenable接口的对象(是一个对象,里面有一个then方法,参数是函数),这个then方法将会作为此次Promise.then

async function func() {
  return {
    then(cb) {
      cb('cb')
    }
  }
}
console.log(func()) // Promise {pending},此时处于初始状态
func().then(console.log) // cb

(6) 可以在异步函数里抛出一个错误会返回一个拒绝的期约对象(reject)

async function err() {
  console.log(1)
  throw new Error('error') // 相当于return,后面的代码不会执行
  console.log(2)
}

err().catch(console.log) // error

(7) 但是,拒绝的期约对象的错误不会被异步函数捕获

async function rej() {
  console.log(1)
  Promise.reject('error1234')
}
console.log(rej())
打印结果:
1
Promise { undefined }
报错
  1. await

(1) await可以暂停和恢复异步函数代码的执行,等待期约解决,再 异步 恢复异步函数的执行(即等待拿到结果后,再异步(恢复)执行后面的代码,相当于await语句后面的代码成了一个异步任务 -------- Promise.then() )

const fun = async () => {
  console.log(3)
  const res = Promise.resolve('123')
  console.log(1)
  console.log('res', res)
  // 这串代码等同于:
  // Promise.resolve('123').then(res => {
  //   console.log(1)
  //   console.log('res', res)
  // })
}
console.log(2)
fun()
打印结果:
2
3
1
res Promise { '123' }

(2) await关键字后面跟Promise实例对象,也可以跟一些常规值

const fun1 = async () => {
  console.log(1)
  const number = await 10
  const string = await '10'
  const arr = await [1, 2, 3]
  const obj = await {
    name: 'dieqi'
  }
  console.log('number', number)
  console.log('string', string)
  console.log('arr', arr)
  console.log('obj', obj)
}
fun1()
打印结果:
1
number 10
string 10
arr [ 1, 2, 3 ]
obj { name: 'dieqi' }

(3) await 后面抛出一个错误对象,会返回一个拒绝的期约对象,注意:await 后面不能直接跟 thorw 关键词,可以包裹一个立即执行函数

const fun3 = async () => {
  console.log(1)
  await (() => {
    throw 3
  })()
}
fun3().catch(console.log)
打印结果:
1
3

(4) await 后面直接跟一个拒绝的期约对象,会直接报错,并终止后面代码的执行

const fun4 = async () => {
  await Promise.reject('123')
  console.log(1) // 此代码不会被执行
}
console.log(fun4()) // 报错信息
fun4().catch(console.log) // 123

  1. await的限制
  • 只能在异步函数中使用,不能在顶级上下文如script中使用
  • await关键字只能在async关键字所在作用域下一级作用域使用
const test = async () => {
  console.log(await 10)
  // 报错 ftn函数不能使用 await 关键字
  const ftn = () => {
    console.log(await 100)
  }
  ftn()
}
test()
  1. example

(1)

 async function foo() {
       console.log(await Promise.resolve('3'))
     }
     
     async function bar() {
       console.log(await '2')
     }
     
     async function baz() {
       console.log('1')
     }
     foo()
     bar()
     baz()
     1
     3
     2
       
/* 
     await会暂停async函数代码的执行,等到拿到结果后才会异步恢复async函数代码的执行,并且await会帮我们将记录在哪里暂停了代码的执行
     
     foo(): 遇到await,暂停代码执行,由于是异步恢复代码执行的,所以async函数后面代码语句的执行是一个异步任务(等同于Promise.then这个异步任务),记为 then1
           此时异步任务队列里面存放 then1 异步任务
     
     bar(): 同 foo(),记为 then2,此时异步任务队列里面 存放 then1(先进来的)   then2(后进来的)
     baz(): async函数里面不包含 await 关键字,跟普通函数没什么区别,是个同步任务,所以打印 1
     
     接着开始执行 异步任务队列里面的异步任务,所以此时执行 then1,await恢复代码的执行,打印3
     接着 then2,打印2
     
     可以这样理解:
     const res = await Promise.reslove(10)
     consose.log(res)
     等同于
     Promise.reslove(10).then(res => {
     	consose.log(res)
     })
     
     */

(2)

async function foo() {
       console.log(2)
       console.log(await Promise.resolve(8))
       console.log(9)
     }
     async function bar() {
       console.log(4)
       console.log(await 6)
       console.log(7)
     }
     
     console.log(1)
     foo()
     console.log(3)
     bar()
     console.log(5)
     // 1 2 3 4 5 8 9 6 7

(3) 实现延迟等待函数

// 实现延迟函数
const sleep =  (time) => {
  return new Promise((reslove,reject) => {
    setTimeout(reslove, time)
  })
}
const test = async () => {
  const now = Date.now()
  await sleep(2000)
  console.log(Date.now()-now)
}
test() // 约等于 2000

(4)实现并行执行

const sleep = (time, i = undefined) => {
  return new Promise((reslove, reject) => {
    setTimeout(() => {
      console.log(time, '第' + i + '元素')
      i !== undefined && reslove(i)
    }, time)
  })
}
// 多个await只会依据顺序执行(串行执行)(代码从上往下执行),即使你们之间没有依赖,
// 但这种情况比较耗时,下一个 await 需要等待上一个 await拿到结果(即执行 resolve或reject函数)
const test = async () => {
  const now = Date.now()
  await sleep(0)
  await sleep(500)
  await sleep(1000)
  await sleep(1500)
  console.log(Date.now() - now) // 约等于 3000
}
test()

对上面的代码改进实现平行执行函数

  1. 在每一个 await 关键词外面包裹一个定时器(延迟0ms),这样就将多个 await 给分割开了,两两之间就不会有影响了

const testImprove = async () => {
  const now = Date.now()
  setTimeout(async () => {
    await sleep(0)
  }, 0)
  setTimeout(async () => {
    await sleep(500)
  }, 0)
  setTimeout(async () => {
    await sleep(1000)
  }, 0)
  setTimeout(async () => {
    await sleep(1500)
    console.log(Date.now() - now) // 约等于 1500
  }, 0)
}
// testImprove()
  1. 先一次性初始化所有Promise实例对象,然后在分别等待它们的结果
// 2. 先一次性初始化所有Promise实例对象,然后在分别等待它们的结果
// why??
// 理解:在初始化的时候就已经将sleep函数里面的异步任务(setTimeout)注册到异步任务的任务队里里面了,
// 等待满足执行的条件(0 500ms 1000ms 1500ms)就会执行setTimeout
//  初始化的时候setTimeout已经开始计时(在遇到await之前)
//  例:当过了 1000ms 后,此时前三个setTimeout已经满足条件了,此时前三个setTimeout打印出 0 500 1000
//  再执行 await p 的时候就不需要在注册异步任务了,只需等待结果即可
const foo = async () => {
  const now = Date.now()
  const p1 = sleep(0)
  const p2 = sleep(500)
  const p3 = sleep(1000)
  const p4 = sleep(1500)

  await p1
  await p2
  await p3
  await p4
  console.log(Date.now() - now) // 约等于 1500
}
// foo()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值