【问题标题】:synchronous and asynchronous loops in javascriptjavascript中的同步和异步循环
【发布时间】: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 开始执行之后,可能直到将来某个时间才会被调用?见stackoverflow.com/help/mcve
  • 看起来会发生的是,为执行异步 I/O 的函数注册的回调 - 例如 - 在 B 执行后被调用。但是,上面的代码是按顺序运行的,稍后会调用您的回调。

标签: javascript


【解决方案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 可能是解决方案,但包含解释确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
      猜你喜欢
      • 1970-01-01
      • 2011-05-16
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 2014-07-06
      • 2021-04-30
      • 2018-10-17
      • 1970-01-01
      相关资源
      最近更新 更多