2016-12-28 34 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>