2016-12-28 99 views
0

在Javascript中,当您编写如下所示的一段代码时,似乎计算机将首先完成整个循环100 000次(可能需要一两秒钟),然后在控制台中转储所有100 000行一枪。我该如何做到这一点,使计算机一次更新控制台一行,每次通过循环?如何在Javascript中实时输出到控制台?

为了澄清,我想实际上能够看到计算机正在做什么,而不是一旦它完成了。

for (var i = 1; i <= 100000; i++) { 
 
    console.log(i); 
 
}

+2

在什么样的环境? Javascript运行在很多不同的地方,有很多不同的'console实现。日志' –

+1

打开chrome开发工具,切换到控制台,粘贴该代码,???,获利! – imjared

+1

我有一种感觉,你在一个有某种启动延迟的环境中工作。即使循环完全在任何日志记录完成之前运行,仅100,000次迭代就不会花费可察觉的时间量... –

回答

2

浏览器同步运行脚本。如果您希望在长期任务运行时更新页面,则需要将长时间运行的同步代码分解为多个部分,并在处理这些部分时将控制权交给浏览器。这意味着您需要处理将一系列任务分解为块,并控制将控制返回给浏览器的延迟。

这里有一个片段,它提供了一个方法,可以让你做到这一点!您会注意到性能仍然不是很好,但我确信这是由于stackoverflow的嵌入式脚本运行器的实现缓慢(console.log)。尝试在浏览器的实际控制台中使用此代码 - 性能非常好!

function doHeavyTask(params) { 
 
    var totalMillisAllotted = params.totalMillisAllotted; 
 
    var totalTasks = params.totalTasks; 
 
    var tasksPerTick = params.tasksPerTick; 
 
    var tasksCompleted = 0; 
 
    var totalTicks = Math.ceil(totalTasks/tasksPerTick); 
 
    var interval = null; 
 
     
 
    if (totalTicks === 0) return; 
 
    
 
    var doTick = function() { 
 
    var totalByEndOfTick = Math.min(tasksCompleted + tasksPerTick, totalTasks); 
 
    
 
    do { 
 
     params.task(tasksCompleted++); 
 
    } while(tasksCompleted < totalByEndOfTick); 
 
     
 
    if (tasksCompleted >= totalTasks) clearInterval(interval); 
 
    }; 
 
    
 
    // Tick once immediately, and then as many times as needed using setInterval 
 
    doTick(); 
 
    if (totalTicks > 1) interval = setInterval(doTick, totalMillisAllotted/totalTicks); 
 
} 
 

 
// Do 10,000 console.logs, in chunks of 100, within 5 seconds 
 
doHeavyTask({ 
 
    totalMillisAllotted: 5 * 1000, 
 
    totalTasks: 10000, 
 
    tasksPerTick: 100, 
 
    task: function(n) { console.log(n + 1); } 
 
});

-1

你的声明是无效的。 JavaScript同步处理for循环。

请检查以下问题:JavaScript, Node.js: is Array.forEach asynchronous?

+1

这与问题没有关系。问题更多的是是否可以立即输出console.log,而不是在循环完成后输出。答案是它取决于环境。例如,使用node.js,是的,它可以:http://stackoverflow.com/a/27900423/2101267 –

+0

@DarkFalcon console.log即刻登录。 – tomepejo

0

如果你想更平滑的输出,我建议避免for循环,而是使用​​将管理时,打印出结果。

var counter = 0; 
var max = 100000; 
function myPrint(){ 
    if(counter < max){ 
     console.log(counter++); 
     requestAnimationFrame(myPrint); 
    } 
} 
myPrint(); 
+1

我不会将'requestAnimationFrame'用于与图形更新无关的任何事情。 –

+0

我同意,这不是最好的建议。我应该补充说'requestAnimationFrame'在nodeJS中不起作用。 – bobjoe

0

for (let i = 1; i <= 10; i++) { 
 
    //console.log(i); 
 
    setTimeout(function(){console.log(i)},i*1000); 
 
}

这里是你如何能耽误您的控制台。使用setTimeout检查1秒(1000毫秒)后console.log值的值。

let允许您将范围受限的变量声明为块,语句或使用它的表达式。这与var关键字不同,var关键字全局定义变量,或在本地定义整个函数,而不考虑块范围。

+0

这是一种破解,但在某些情况下我可以利用它。尝试将时间更改为10ms以获得一些有趣的结果。 – neoflash

+0

在10ms内加载速度很快,结果仍然保持不变。你使用铬? – jindhk

+0

是的,铬。在JSfiddle中尝试它,它不会按顺序将它们全部打印出来。 – neoflash

0

人们可以以达到期望的结果馈送承诺的阵列到可观察。 Promise现在是JavaScript的原生代码,您可以从RxJS库中获取Observable。

下面是一个例子:

const array = []; 
 

 
// This could also be a for of loop or a .map() function 
 
for (let i = 0; i <= 25; i++) { 
 
    const promise = new Promise((resolve) => { 
 

 
    // This could be any synchronous or asynchronous code 
 
    setTimeout(() => { 
 
     resolve(i); 
 
    }, 1000 * i); 
 
    }); 
 

 
    array.push(promise); 
 
} 
 

 
var observable = Rx.Observable.from(array); 
 

 
observable.subscribe((promise) => { 
 
    promise.then(result => console.log(result)); 
 
});
<script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script>