有一個過程需要經過多個function計算後才能得出結果
而這一個過程會每隔一段時間就loop一次
ex.
第2個function需要第1個function計算過的資料
第3個function需要第2個function計算過的資料
以此類推...
這些function需要用同步的方式順序執行
最後會需要用計算出資料繪製在canvas上顯示出來
假設1個function可能要花掉50~100ms
因此會造成畫面上的狀態有卡頓的狀況發生
目前只想到將計算過程放到settimeout的callback中
這是我的範例
一個不斷上下移動的方塊,顯示計算對畫面造成阻塞的影響
<style>
.rectangle {
	position: absolute;
	left: 50%;
	width: 150px;
	height: 150px;
	transform: translateX(-50%);
	text-align: center;
	background-color: #2196f3;
	animation: move  infinite  5s  linear;
}
@keyframes  move {
	0% {top: 5%;background-color: #2196f3;}
	50% {top: 80%;background-color: #9e9e9e;}
	100% {top: 5%;background-color: #2196f3;}
}
</style>
<body>
	<div  class="rectangle">TEST</div>
	<div  id="state"></div>
</body>
function  computeProcess(len) {
	state.innerHTML  =  ""
	for (let  i  =  0; i  <  len; i++) {
		state.innerHTML  =  i;
	}
}
function  timeOut(callback, timer) {
	setTimeout(() => {
		callback();
	}, timer);
}
function  loop() {
    // 會阻塞造成畫面卡頓
	setTimeout(() => {
		computeProcess(10000); // 第1個function
		computeProcess(10000); // 第2個function
		computeProcess(10000); // 第3個function
		loop();
	}, 300);
	// 解決卡頓的作法???
	timeOut(() => {
		computeProcess(10000);
		timeOut(() => {
			computeProcess(10000);
			timeOut(() => {
			computeProcess(10000);
				timeOut(() => {
					loop();
				}, 300);
			}, 0);
		}, 0);
	}, 0);
}
loop();
但這樣變成Callback Hell,所以我現在是改成這樣做
讓function照順序執行然後也不要畫面有卡頓的狀況發生
不知道有沒有更好的方法?
function timeOut(callback, timer) {
	return new Promise((resolve) => {
		setTimeout(() => {
			callback();
			resolve();
		}, timer);
	});
}
function loop(){
	(async () => {
		await  timeOut(() => {
			computeProcess(10000);
		}, 0);
		await  timeOut(() => {
			computeProcess(10000);
		}, 0);
		await  timeOut(() => {
			computeProcess(10000);
		}, 0);
		await  timeOut(() => {
			loop();
		}, 300);
	})();
}
30 Seconds of Knowledge - chainAsync
如果我沒理解錯誤的話,您或許能參考上方的資源。
Web Workers 提供簡單的方法讓網頁在背景執行緒 (Thread) 中執行程式
運算量大的東西可以考慮丟給 Web Worker 跑
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <div id="r">處理中</div>
</body>
</html>
<script>
  function delay(n){
      return new Promise(function(resolve){
          setTimeout(resolve,n*1000);
      });
  }
  
  let fn1 = async () => {
    await delay(3)  // delay請當成大量運算的時間
    return 3
  }
  
  let fn2 = async (i) => {
    await delay(2)
    return i * 3
  }
  
  // 統合fn1、fn2,並等待fn2完成後發送事件告訴傳入的DOM該更新了。
  let fn3 = async (elm) => {
    const r1 = await fn1()
    const r2 = await fn2(r1)
    elm.dispatchEvent(new CustomEvent("onResult", {
        detail: {r2: r2}
      }));
  }
  
  const resultDisplay = document.querySelector("#r")
  // 註冊事件
  resultDisplay.addEventListener("onResult", function(e){
    this.innerText = e.detail.r2
  })
  
  // 執行
  fn3(resultDisplay)
</script>
https://jsbin.com/yujenaheti/edit?html,output
老慣例,ie一樣不能跑。
你要的大概是這樣吧。
delay的部份只是為了模擬運算時間。
真正大量運算的話用上面說的 Web Workers。
然後在javascript請盡量用event代替setTimeout...
你能確定你的運算不會delay到連你timeout的時間都超過?
稍微改一下code結構,為了解耦合。
不確定會不會delay到,不太清楚用event代替settimeout的意思是甚麼。
想問個,只要把耗時間的計算動作拆開,讓中間產生空檔讓GUI有空檔可以重新重繪,我的理解不知有沒有錯。
我能拆分的最小單位就是opencv.js的api,一個api的花掉的時間應該不多。
你注意看我的code,除了為了模擬大量運算的delay,應該沒有用到setTimeout的地方吧?
如果你都用setTimeout去等運算完成,你會遇到幾個問題:
因此最好的策略就是運算完就反應,而不是用setTimeout這種你無法掌握的方式。
如果你需要固定時序更新,可以先存到一個cache,定時取出更新。
我的code簡單的說就是首先先對#r註冊一個自訂事件(onResult),當這事件發生時,會更新畫面。
用fn3去等fn1、2的依序運算完成,觸發(dispatchEvent)一個自訂事件(onResult)。