zl程序教程

您现在的位置是:首页 >  Javascript

当前栏目

JS循环中使用async、await的正确姿势

2023-02-18 16:30:21 时间

概览(循环方式 - 常用)

  • for
  • map
  • forEach
  • filter

声明遍历的数组和异步方法

声明一个数组:⬇️

const skills = ['js', 'vue', 'node', 'react']

再声明一个promise的异步代码: ⬇️

function getSkillPromise (value) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(value)
    }, 1000)
  })
}

for 循环中使用

由于for循环并非函数,而asyncawait需要在函数中使用,因此需要在for循环外套一层function

async function test () {
  for (let i = 0; i < skills.length; i++) {
    const skill = skills[i]
    const res = await getSkillPromise(skill)
    console.log(res)
  }
}

test() // 调用

当使用await时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。上述结果意味着for循环中有异步代码,是可以等到for循环中异步代码完全跑完之后再执行for循环后面的代码。 但是他不能处理回调的循环,如forEachmapfilter等,下面具体分析。

map 中使用

map中使用await, map 的返回值始是promise数组,这是因为异步函数总是返回promise

async function test () {
  console.log('start')
  const res = skills.map(async item => {
    return await getSkillPromise(item)
  })
  console.log(res)
  console.log('end')
}

test()

结果:始终为promise数组

start
[
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> }
]
end

若果你想要等到promise的返回结果,可以使用promise.all()处理一下

async function test () {
  console.log('start')
  const res = skills.map(async item => {
    return await getSkillPromise(item)
  })
  const resPromise = await Promise.all(res)
  console.log(resPromise)
  console.log('end')
}

test()

// 结果
start
[ 'js', 'vue', 'node', 'react' ]
end

forEach 中使用

先上代码和结果

async function test () {
  console.log('start')
  skills.forEach(async item => {
    const res = await getSkillPromise(item)
    console.log(res)
  })
  console.log('end')
}

test()

预期结果

'Start'
'js'
'vue'
'node'
'react'
'End'

实际结果 在forEach循环等待异步结果返回之前就执行了console.log('end')

'Start'
'End'
'js'
'vue'
'node'
'react'

JavaScript 中的 forEach不支持 promise 感知,也支持 asyncawait,所以不能在 forEach 使用 await

filter 中使用

使用filter过滤itemvue或者react的选项

正常使用 filter

async function test () {
  console.log('start')
  const res = skills.filter(item => {
    return ['vue', 'react'].includes(item)
  })
  console.log(res)
  console.log('end')
}

test() // 调用

// 结果
start
[ 'vue', 'react' ]
end

使用 await后:

async function test () {
  console.log('start')
  const res = skills.filter(async item => {
    const skill = await getSkillPromise(item)
    return ['vue', 'react'].includes(item)
  })
  console.log(res)
  console.log('end')
}

test()

预期结果:

start
[ 'vue', 'react' ]
end

实际结果:

[ 'js', 'vue', 'node', 'react' ]
end

结论:因为异步函数getSkillPromise返回结果返回的promise总是真的,所以所有选项都通过了过滤