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 ...

使用forB 的执行有时会在A 之前开始......(所以异步)

有没有办法以同步方式使用语句?

【问题讨论】:

"使用forB的执行有时会在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(() =&gt; /*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中的循环函数(如whilefor.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 callbackfunction 中的代码带有async 关键字或带有callback(不是全部)的一些本机函数,例如setTimeoutsetIntervaletc异步运行

例子:

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中的同步和异步循环的主要内容,如果未能解决你的问题,请参考以下文章

同步异步和Event loop事件循环

js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

JavaScript事件循环:同步任务和异步任务

浏览器中的JavaScript事件循环机制

JavaScript:彻底理解同步异步和事件循环(Event Loop)

JavaScript:彻底理解同步异步和事件循环(Event Loop) (转)