Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/407.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 与普通for循环相比,数组的forEach是异步的_Javascript_Asynchronous_Ecmascript 6_Promise - Fatal编程技术网

Javascript 与普通for循环相比,数组的forEach是异步的

Javascript 与普通for循环相比,数组的forEach是异步的,javascript,asynchronous,ecmascript-6,promise,Javascript,Asynchronous,Ecmascript 6,Promise,我刚开始探索es6中的async/await,我发现了一些令我惊讶的事情。基本上,forEach异步运行,而for循环同步运行就是一个例子 function getData(d) { return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(d.x+" %%%% ") },1000) }) } const data=[{x:"aaa"},{x:

我刚开始探索es6中的
async/await
,我发现了一些令我惊讶的事情。基本上,
forEach
异步运行,而
for
循环同步运行就是一个例子

function getData(d) {
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(d.x+" %%%% ")
        },1000)
    })
}
const data=[{x:"aaa"},{x:"bbb"}]


//async for loop
const makeRequest1 = async () => {
    for (let i in data){
        let value=data[i]
        console.log(value)
        value.p=await getData(value)
        console.log(JSON.stringify(value)+ ' after')
    }
    // console.log(rr)
    console.log(data)
    console.log("Is it block ??")
    return "done"
}
// { x: 'aaa' }
// {"x":"aaa","p":"aaa %%%% "} after
// { x: 'bbb' }
// {"x":"bbb","p":"bbb %%%% "} after
// [ { x: 'aaa', p: 'aaa %%%% ' }, { x: 'bbb', p: 'bbb %%%% ' } ]
// Is it block ??
//     done



//async for loop
const makeRequest2 = async () => {
    data.forEach(async (value)=>{
        console.log(value)
        value.p=await getData(value)
        console.log(JSON.stringify(value)+ ' after')
    })
    console.log(data)
    console.log("Is it block ??")
    return "done"
}
// { x: 'aaa' }
// { x: 'bbb' }
// [ { x: 'aaa' }, { x: 'bbb' } ]
// Is it block ??
// done
// {"x":"aaa","p":"aaa %%%% "} after
// {"x":"bbb","p":"bbb %%%% "} after


makeRequest2().then((r)=>{
    console.log(r)
})

我知道
for
forEach
版本应该同步运行,为什么
forEach
在这种情况下会变得异步

从承诺的角度考虑(这就是async/await真正的含义)

在第一种情况下,你就像你会做的那样,把承诺连在一起

getData(data[0])
  .then((val) => console.log(...))
  .then(() => getData(data[1])
  .then(...
在第二种情况下,您只是一次调用所有承诺,因为
forEach
会立即运行并注册所有承诺:

data.forEach(x => getData(x).then(val => console.log(...)));
注意,在这种情况下,getData(1)实际上并不等待getData(0)完成—没有链接。forEach中的等待只是在每个承诺中链接了一个then,并且只捕获forEach中的下一段代码

这意味着在第二种情况下,这些承诺将彼此异步运行

如果您确实希望这样做,但希望等待所有调用完成(使用第二种方法),则只需承诺即可。all+map方法:

const res = await Promise.all(data.map(item => getData(item)));
这将有效地在结果数组中的数组中的每个项上带来来自getData的所有结果,但请记住,这些调用都是异步的

此外,无法使用标准的forEach使函数互相等待。您可以使用
reduce
操作来代替:

await data.reduce((intermPromise, item) => intermPromise.then(getData(item)), Promise.resolve());
这基本上是通过减少数组(从单元承诺开始)来链接对每个项的调用。最终外部等待将应用于与所有呼叫链接的最终承诺

还要注意使用
map
方法与
reduce
方法之间的区别,前者可以轻松地获得数组中的所有结果(但它是异步运行的),后者可以获得同步调用,但最终结果不会返回数组,实际上它只返回最后一次调用的结果


希望这有帮助。

可能是因为回调前的
async
。@Weedoze非常可能,您是否有任何详细解释,您说您正在探索
async
wait
,然后去阅读文档。这将为您提供一个解释,您要传递给
的异步函数。forEach
与外部异步函数不同步。
for
案例只有一个异步函数,因此有明确的顺序。@loganfsmyth谢谢你指出了方向,我感觉我理解你在说什么,但不完全理解。我需要阅读更多的文档,希望能得到一些提示