使用JavaScript怎麼實作一個非同步任務佇列,並依序處理佇列中的所有任務?本篇文章為大家介紹JavaScript 阻塞方式實作非同步任務佇列的方法。
有個需求,需要實作一個非同步任務佇列,並依序處理佇列中的所有任務,具體如下:
隨機時間增加非同步任務到佇列中
#佇列中的任務依照先進先出的規則依序執行
任務為非同步請求,等一個執行完了再執行下一個
這個需求若使用Java語言的BlockingQueue很容易實現,但是JavaScript沒有鎖定機制,實現起來就不那麼容易。
很容易想到使用同步非阻塞方案,每隔一定的時間去偵測一下佇列中有無任務,有則取出第一個處理。這裡偵測間隔間隔500毫秒,使用setTimeout模擬非同步請求。
<body> <button onclick="clickMe()">点我</button> </body>
let queue = [] let index = 0 function clickMe() { queue.push({name: 'click', index: index++}) } run() async function run() { while (true) { if (queue.length > 0) { let obj = queue.shift() let res = await request(obj.index) console.log('已处理事件' + res) } else { await wait(500) console.log('----- 队列空闲中 -----') } } } // 通过setTimeout模拟异步请求 function request(index) { return new Promise(function (resolve, reject) { setTimeout(() => { resolve(index) }, 1000) }) } function wait(time) { return new Promise(function (resolve) { setTimeout(() => { resolve() }, time) }) }
但是這個方案有2個問題。
那有沒有像Java中BlockingQueue那樣的佇列空閒就阻塞,不消耗資源的處理方式呢?
主要思路:
<body> <button onclick="clickMe()">点我</button> </body>
// 异步请求队列 const queue = [] // 用来模拟不同的返回值 let index = 0 // 标志是否正在处理队列中的请求 let running = false // 使用setTimeout模拟异步请求 function request(index) { return new Promise(function (resolve) { setTimeout(() => { resolve(index) }, 1000) }) } // 连续点击,触发异步请求,加入任务队列 function clickMe() { addQueue(() => request(index++)) } // 当队列中任务数大于0时,开始处理队列中的任务 function addQueue(item) { queue.push(item) if (queue.length > 0 && !running) { running = true process() } } function process() { const item = queue.shift() if (item) { item().then(res => { console.log('已处理事件' + res) process() }) } else { running = false } }
利用好Promise沒有resolve會一直阻塞的特性,可以實現類似Java的BlockingQueue的功能,非同步任務依序執行,且佇列空閒也不消耗資源。
更多程式相關知識,請造訪:程式設計影片! !
以上是淺談JS阻塞方式怎麼實現非同步任務隊列?的詳細內容。更多資訊請關注PHP中文網其他相關文章!