阅读本文大约需要 9 分钟与的使用方式相对简单。 当你尝试在循环中使用时,事情就会变得复杂一些。
在本文中,分享一些在如果循环中使用值得注意的问题。
[h1]准备一个例子[/h1]对于这篇文章,假设你想从水果篮中获取水果的数量。- const fruitBasket = { apple: 27, grape: 0, pear: 14};
复制代码 你想从获得每个水果的数量。 要获取水果的数量,可以使用函数。- const getNumFruit = fruit => { return fruitBasket[fruit];};const numApples = getNumFruit('apple');console.log(numApples); //27
复制代码 现在,假设是从服务器上获取,这里我们使用来模拟。- const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms))};const getNumFruie = fruit => { return sleep(1000).then(v => fruitBasket[fruit]);};getNumFruit("apple").then(num => console.log(num)); // 27
复制代码 最后,假设你想使用和来获取异步函数中每个水果的数量。- const control = async _ => { console.log('Start') const numApples = await getNumFruit('apple'); console.log(numApples); const numGrapes = await getNumFruit('grape'); console.log(numGrapes); const numPears = await getNumFruit('pear'); console.log(numPears); console.log('End')}
复制代码
[h1]在 for 循环中使用 await[/h1]首先定义一个存放水果的数组:- const fruitsToGet = [“apple”, “grape”, “pear”];
复制代码 循环遍历这个数组:- const forLoop = async _ => { console.log('Start'); for (let index = 0; index < fruitsToGet.length; index++) { // 得到每个水果的数量 } console.log('End')}
复制代码 在循环中,过上使用来获取每个水果的数量,并将数量打印到控制台。
由于返回一个,我们使用来等待结果的返回并打印它。- const forLoop = async _ => { console.log('start'); for (let index = 0; index < fruitsToGet.length; index ++) { const fruit = fruitsToGet[index]; const numFruit = await getNumFruit(fruit); console.log(numFruit); } console.log('End')}
复制代码 当使用时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。这意味着循环中的应该按顺序执行。
结果正如你所预料的那样。- “Start”;“Apple: 27”;“Grape: 0”;“Pear: 14”;“End”;
复制代码
这种行为适用于大多数循环(比如和循环)…
但是它不能处理需要回调的循环,如、、和。在接下来的几节中,我们将研究如何影响、map和。
[h1]在 forEach 循环中使用 await[/h1]首先,使用对数组进行遍历。- const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End')}
复制代码 接下来,我们将尝试使用获取水果数量。 (注意回调函数中的关键字。我们需要这个关键字,因为在回调函数中)。- const forEachLoop = _ => { console.log('Start'); fruitsToGet.forEach(async fruit => { const numFruit = await getNumFruit(fruit); console.log(numFruit) }); console.log('End')}
复制代码 我期望控制台打印以下内容:- “Start”;“27”;“0”;“14”;“End”;
复制代码 但实际结果是不同的。在循环中等待返回结果之前,JavaScrip先执行了 console.log('End')。
实际控制台打印如下:
JavaScript 中的不支持 promise 感知,也不支持和,所以不能在使用。
[h1]在 map 中使用 await[/h1]如果在中使用,始终返回数组,这是因为异步函数总是返回。- const mapLoop = async _ => { console.log('Start') const numFruits = await fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit; }) console.log(numFruits); console.log('End')}“Start”;“[Promise, Promise, Promise]”;“End”;
复制代码
如果你在中使用,总是返回,你必须等待数组得到处理。 或者通过- await Promise.all(arrayOfPromises)
复制代码 来完成此操作。- const mapLoop = async _ => { console.log('Start'); const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit; }); const numFruits = await Promise.all(promises); console.log(numFruits); console.log('End')}
复制代码 运行结果如下:
如果你愿意,可以在中处理返回值,解析后的将是返回的值。- const mapLoop = _ => { // ... const promises = fruitsToGet.map(async fruit => { const numFruit = await getNumFruit(fruit); return numFruit + 100 }) // ...}“Start”;“[127, 100, 114]”;“End”;
复制代码 [h1]在 filter 循环中使用 await[/h1]当你使用时,希望筛选具有特定结果的数组。假设过滤数量大于20的数组。
如果你正常使用(没有 await),如下:- const filterLoop = _ => { console.log('Start') const moreThan20 = fruitsToGet.filter(async fruit => { const numFruit = await fruitBasket[fruit] return numFruit > 20 }) console.log(moreThan20) console.log('END')}
复制代码 运行结果中的不会以相同的方式工作。 事实上,它根本不起作用。- const filterLoop = async _ => { console.log('Start') const moreThan20 = await fruitsToGet.filter(async fruit => { const numFruit = fruitBasket[fruit] return numFruit > 20 }) console.log(moreThan20) console.log('END')}// 打印结果Start["apple", "grape", "pear"]END
复制代码
为什么会发生这种情况?
当在回调中使用时,回调总是一个。由于总是真的,数组中的所有项都通过。在使用类以下这段代码- const filtered = array.filter(true);
复制代码 在使用正确的三个步骤
- 使用返回一个promise 数组
- 使用等待处理结果
- 使用对返回的结果进行处理
- const filterLoop = async _ => { console.log('Start'); const promises = await fruitsToGet.map(fruit => getNumFruit(fruit)); const numFruits = await Promise.all(promises); const moreThan20 = fruitsToGet.filter((fruit, index) => { const numFruit = numFruits[index]; return numFruit > 20; }) console.log(moreThan20); console.log('End')}
复制代码
[h1]在 reduce 循环中使用 await[/h1]如果想要计算中的水果总数。 通常,你可以使用循环遍历数组并将数字相加。- const reduceLoop = _ => { console.log('Start'); const sum = fruitsToGet.reduce((sum, fruit) => { const numFruit = fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End')}
复制代码 运行结果:
当你在中使用时,结果会变得非常混乱。- const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (sum, fruit) => { const numFruit = await fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End')}
复制代码 是什么 鬼??
剖析这一点很有趣。
- 在第一次遍历中,为。是(通过的得到的值),。
- 在第二次遍历中,是一个。 (为什么?因为异步函数总是返回!)是.promise 无法正常添加到对象,因此JavaScript将其转换为字符串。是。
- 在第三次遍历中,也是一个。是.是。
解开谜团!
这意味着,你可以在回调中使用,但是你必须记住先等待累加器!- const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => { const sum = await promisedSum; const numFruit = await fruitBasket[fruit]; return sum + numFruit; }, 0) console.log(sum) console.log('End')}
复制代码
但是从上图中看到的那样,操作都需要很长时间。 发生这种情况是因为需要等待每次遍历完成。
有一种方法可以加速循环,如果你在等待promisedSum之前先等待,那么只需要一秒钟即可完成:- const reduceLoop = async _ => { console.log('Start'); const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => { const numFruit = await fruitBasket[fruit]; const sum = await promisedSum; return sum + numFruit; }, 0) console.log(sum) console.log('End')}
复制代码
这是因为可以在等待循环的下一个迭代之前触发所有三个promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
- 使用返回一个promise 数组
- 使用等待处理结果
- 使用对返回的结果进行处理
- const reduceLoop = async _ => { console.log('Start'); const promises = fruitsToGet.map(getNumFruit); const numFruits = await Promise.all(promises); const sum = numFruits.reduce((sum, fruit) => sum + fruit); console.log(sum) console.log('End') }
复制代码 这个版本易于阅读和理解,需要一秒钟来计算水果总数。
[h1]从上面看出来什么[/h1]- 如果你想连续执行调用,请使用循环(或任何没有回调的循环)。
- 永远不要和一起使用,而是使用循环(或任何没有回调的循环)。
- 不要在和中使用,如果需要,先用进一步骤处理,然后在使用和进行处理。
文章来自 sf 的小智,有兴趣可以关注他的公众号「大迁世界」 原文链接:https://segmentfault.com/a/1190000019357943 「一个有温度的前端号」
长按识别二维码关注
点赞分享是对作者最大的支持!
|
|