“JavaScript 循环中的 ‘await‘

128 阅读3分钟

“JavaScript 循环中的 ‘await‘

目录

[TOC]

前言

在JavaScript的forEach方法中使用await是无效的,因为forEach方法不支持异步操作的等待。

forEach是一个数组的遍历方法,它会对数组中的每个元素依次执行提供的回调函数。而在JavaScript中,await关键字只能在异步函数(async函数)中使用,用于等待一个Promise对象的解析结果。

forEach的回调函数中使用await关键字,实际上会导致它被忽略,无法正确地等待异步操作的完成。这是因为forEach不会等待回调函数中的异步操作完成,而是立即执行下一个回调函数。

如果你需要在数组的每个元素上执行异步操作,并等待每个操作完成,可以考虑使用for...of循环结合await关键字(异步循环),或者使用map方法结合Promise.all方法来处理异步操作(并行请求)。

Promise.all() 方法不能保证 Promise 对象的执行顺序,它只能确保所有的 Promise 对象都被解析后才会触发后续的处理。

虽然 Promise.all() 方法会等待所有的 Promise 对象都被解析,但它并不能保证上传操作的顺序。上传操作的顺序是可能会受到网络延迟等因素的影响,导致后续的处理可能会在某些上传操作完成之前就开始执行。 但是 Promise.all()所以异步成功后返回的数组是对应关系

如果你希望确保上传操作按照数组中的顺序执行,可以考虑使用 for...of 循环,并等待每个上传操作完成后再处理下一个元素。

注意:

  1. for :要使用在 async 异步方法里,循环会等 await 执行而停留, await 是有效的,有 break
  2. forEach :没有 break ,循环不会等 await 执行而停留, await 是无效的;
  3. for of :要使用在 async 异步方法里,执行期间, await 之前的代码会执行,到了 await 会等待 await 执行完才继续往下执行,有 break
  4. for await of :也要用在 async 异步方法里,有 break ,但是它一般是使用在 item 是个异步方法的情况下,并不常见,场景如下面对应的例子,要遍历的数组元素是个异步请求,异步没回来之前整个 for 循环代码不执行。

for使用await -- 有效的 (非并非)

<script>
    let arr = ["我", "爱", "编", "程"]
    function getDatas(e) {
        return axios.get(`https://api.oioweb.cn/api/txt/dict?text=${e}`)
    }
    async function execute() {
        for (let i = 0; i < arr.length; i++) {
            console.log(`第${i + 1}次${arr[i]}执行了`)
            let datas = await getDatas(arr[i])
            console.log("返回结果:" + datas.data.result.words)
            console.log(`第${i + 1}次${arr[i]}执行完了`)
            console.log("---------end--------------")
        }
    }
    execute()
 
</script>

forEach使用await --  无效的  (并发)

<script>
    let arr = ["我", "爱", "编", "程"]
    function getDatas(e) {
        return axios.get(`https://api.oioweb.cn/api/txt/dict?text=${e}`)
    }
    async function execute() {
        arr.forEach(async (item, index) => {
            console.log(`第${index + 1}次${item}执行了`)
            let datas = await getDatas(item)
            console.log("返回结果:" + datas.data.result.words)
            console.log(`第${index}次${item}执行完了`)
            console.log("---------end--------------")
        })
    }
    execute()
 
</script>
可以看到 `forEach` 中使用 `await` 是无效的,只不过 `await` 后面的代码能按顺序执行;

for of 使用await 有效的(非并发)

<script>
    let arr = ["我", "爱", "编", "程"]
    function getDatas(e) {
        return axios.get(`https://api.oioweb.cn/api/txt/dict?text=${e}`)
    }
    async function execute() {
        let index = 0
        for (const item of arr) {
            console.log(`第${index + 1}次${item}执行了`)
            let datas = await getDatas(item)
            console.log("返回结果:" + datas.data.result.words)
            console.log(`第${index + 1}次${item}执行完了`)
            console.log("---------end--------------")
            index += 1
        }
 
    }
    execute()
 
</script>

for await of 使用await 有效的 (并发)

是等待所有的异步完成以后依次执行循环

<script>
 
    function getDatas(e) {
        return axios.get(`https://api.oioweb.cn/api/txt/dict?text=${e}`)
    }
    let arr = [getDatas("我"), getDatas("爱"), getDatas("编"), getDatas("程")]
    async function execute() {
        let index = 0
        for await (const item of arr) {
            console.log(`第${index + 1}次,方法${index + 1}执行了`)
 
            console.log("返回结果:" + item.data.result.words)
            console.log(`第${index + 1}次方法${index + 1}执行完了`)
            console.log("---------end--------------")
            index += 1
        }
 
    }
    execute()
 
</script>

promise.all+map 有效的(并发)

并行,但是可以确认是否全部上传成功,全部成功后在做某些事 最终结果是跟循环的顺序一致的

 
<script>
 
    let url = ` https://api.oioweb.cn/api/txt/dict?text=我`
    let arr = [url, url, url, url,]
 
    function getDatas(url) {
        return axios.get(url)
    }
    let newsArr = arr.map(async item => {
        return await getDatas(item)
 
    })
 
    Promise.all(newsArr).then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err);
    })
 
 
 
</script>
 

总结

  • 实际开发中我们可以发现其实 forwhilefor infor offor await of 使用 await 都是生效的;
  • 而几乎有回调的遍历方法: forEachmapfilterreducesomeeveryfind 等,使用 await 都是不生效的;