javascript中的同步和异步循环
Posted
技术标签:
【中文标题】javascript中的同步和异步循环【英文标题】:synchronous and asynchronous loops in javascript 【发布时间】:2017-06-29 15:01:33 【问题描述】:javascript 中的循环是同步的还是异步的? (对于,同时等)
假设我有:
for(let i=0; i<10; i++)
// A (nested stuff...)
// B ...
使用for
,B
的执行有时会在A
之前开始......(所以异步)
有没有办法以同步方式使用语句?
【问题讨论】:
"使用for
,B
的执行有时会在A
之前开始"你能创建一个stacksn-ps来演示吗?
@guest271314 它可以是任何东西,更多的嵌套语句、ajax、逻辑等
for
循环是同步的。 B
不应在 for
循环完成之前执行。你能证明B
“somtimes”在for
循环完成之前开始执行的情况吗? for
循环中是否有异步操作,在 B
开始执行之后,可能直到将来某个时间才会被调用?见***.com/help/mcve。
看起来会发生的是,为执行异步 I/O 的函数注册的回调 - 例如 - 在 B 执行后被调用。但是,上面的代码是按顺序运行的,稍后会调用您的回调。
JavaScript, Node.js: is Array.forEach asynchronous?的可能重复
【参考方案1】:
在所有异步操作开始时,for 循环会立即运行完成。
好吧,这里我们有一些嵌套循环。请注意,“BBB”总是在之后触发。
for(let i=0; i<10; i++)
for(let i=0; i<10; i++)
for(let i=0; i<10; i++)
console.log("AA")
console.log('BBB')
现在,看看这个
for(let i=0; i<10; i++)
setTimeout(function() console.log("AA"), 2000)
console.log('BBB')
这是因为所谓的“事件循环”。事实上,使用那个 setTimeout 我们正在模拟一个异步操作。它可能是一个 ajax 调用或其他一些异步进程。
看看这个:http://latentflip.com/loupe
这将真正帮助您理解这些异步/同步循环主题。
已更新以显示 Promise 在这里的工作方式(给定下面的 cmets):
var stringValues = ['yeah', 'noooo', 'rush', 'RP'];
var P = function(val, idx)
return new Promise(resolve => setTimeout(() => resolve(val), 1000 * idx));
;
// We now have an array of promises waiting to be resolved.
// The Promise.all basically will resolve once ALL promises are
// resolved. Keep in mind, that if at any time something rejects
// it stops
// we iterator over our stringValues array mapping over the P function,
// passing in the value of our array.
var results = Promise.all(stringValues.map(P));
// once all are resolved, the ".then" now fires. It is here we would do
results.then(data =>
console.log(data) //["yeah", "noooo", "rush", "RP"]
);
如果我不够清楚,请告诉我。
【讨论】:
我应该创建一个类似承诺的东西吗?在间隔之后解决? 好吧,不在你原来的问题中,因为给定一个标准循环 - 它总是会在“BBB”发生之前运行完成。但是,我的猜测是您有某种“可能需要一些时间”的异步操作,然后出现“BBB”,对吗? 这很棒。但是如果我想跳出循环怎么办? darnit 这不是一个“同步”类型的循环——所有的超时都同时被触发;只是1000 * idx
错开的等待
你可以添加一个休息;陈述。不要使用 let i,而是使用 let a,b,c ,a 用于第一个循环,b 用于第二个等等。然后,例如,在内部循环类型中:if (a >= 1) break;,你会看到循环的其他部分没有运行。是这个意思吗?【参考方案2】:
如果您将异步循环放置在 for...loop
中并希望在每个操作结束之前停止循环,则必须使用 async/await
这样的语法。
async function foo()
var array = [/* some data that will be used async*/]
//This loop will wait for each next() to pass the next iteration
for (var i = 0; i < array.length; i++)
await new Promise(next=>
someAsyncTask(array[i], function(err, data)
/*.... code here and when you finish...*/
next()
)
)
foo().then(() => /*After foo execution*/ )
【讨论】:
foo() 之后的任何代码都将在循环内的someAsyncTask
之前运行。
@tiomno 是的,那是因为 foo 是一个 Promise,只需将该代码放入 foo().then(() => /*Your code here*/ )
谢谢!这是一个真正的异步循环,因为每次运行在触发之前都在等待前一个。当满足条件时,我可以通过简单地跳过someAsyncTask()
函数调用但仍执行next()
来“跳过”,这样then..
部分无论如何都会完成。这应该是选择的答案。
在这个方法中,如果我也想用我的someAsyncTask
增加一些延迟......最好的方法是什么?
@GauravAgrawal await new Promise(res => setTimeout(() => res(), 3000))【参考方案3】:
let items = YourArray;
let i = 0;
await new Promise(async (resolve, reject) =>
try
if (items.length == 0) return resolve();
let funSync = async () =>
await yourASyncFunctions(items[i].doAnything);
i++;
if (i == items.length) resolve();
else funSync();
funSync();
catch (e)
reject(e);
);
【讨论】:
【参考方案4】:首先,您关于“用于执行 B 的声明有时会在 A 之前开始......(所以异步)” 是错误的。
Javascript中的循环函数(如while
、for
、.forEach
或.map
)将同步运行(阻塞),无论你是在 Browser 还是在 NodeJS 之类的 Runtime Environment 中运行它。我们可以通过运行下面的代码来证明这一点(这个过程可能需要几秒钟):
let counter1 = 0
let counter2 = 0
let counter3 = 0
console.log("Start iteration")
console.time("Time required")
// First heavy iteration
for (let i = 0; i < 1000; i++)
counter1 += 1
// Second heavy iteration
for (let i2 = 0; i2 < 1000; i2++)
counter2 += 1
// Third heavy iteration
for (let i3 = 0; i3 < 1000; i3++)
counter3 += 1
console.log("Iteration was successful")
console.timeEnd("Time required")
console.log('The value of `counter1` is: ' + counter1)
console.log('The value of `counter2` is: ' + counter2)
console.log('The value of `counter3` is: ' + counter3)
那么什么样的循环会导致你的代码异步运行(非阻塞)?
答案是:
放置在
Promise
callback 或function
中的代码带有async
关键字或带有callback(不是全部)的一些本机函数,例如setTimeout
、setInterval
和 etc 将异步运行。
例子:
setTimeout(() =>
console.log('A')
)
console.log('B')
在代码中,
setTimeout
函数首先被声明。但是,代码的输出显示console.log('B')
函数比setTimeout
函数运行得更早。
【讨论】:
【参考方案5】:for(const elment of arrayElements)
await yourFunc(elment)
await yourOtherFunc('somePatameter')
【讨论】:
虽然此代码 sn-p 可能是解决方案,但包含解释确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。以上是关于javascript中的同步和异步循环的主要内容,如果未能解决你的问题,请参考以下文章
js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)