2017-10-28 198 views
0

假設我們有一個Web服務器接收http請求併發迴響應。它有很多端點,包括這一個如何阻止事件循環直到完成運行異步任務

/task應該有一些異步任務,如從Redis讀/寫,我想阻止事件循環,直到這些任務完成。我知道這是不合理的,因爲事件循環還需要繼續努力以接收Redis的事件。所以我想把這個邏輯放在一個單獨的腳本中,並使用child_process.spawnSync來執行並等待它並阻止當前的事件循環。這個解決方案可以工作,但我的問題是我的邏輯,異步任務比本示例中提到的更復雜,它們依賴於當前腳本,它們是框架的一部分,將它們分離爲單獨的腳本並不容易。有什麼建議麼 ?

var express = require('express'); 
var app = express(); 
var redis = require('./redis'); 

// Block the event loop until finish doing some async tasks 
app.get('/task', function(req, res) { 

    // Block the event loop now 
    redis.get('backup', function(error, backup) { 

    // ...... Do some changes to the backup data 

    redis.set('backup', backup, function(error, result) { 

     // Unblock the event loop now 
     res.send('I am done'); 

    }); 

    }); 

}); 

// To check if the event loop is really blocked 
counter = 0; 
setInterval(() => { console.log(counter++) }, 100); 

app.listen(5000); 
+2

'有什麼建議?',是的。不要阻止。目前還不清楚爲什麼在你的描述中你也需要.. – Keith

+0

爲什麼我需要阻止並不重要,問題在於如何。無論如何,我需要將一些會話狀態備份到Redis中,並防止接收可能導致這些數據無效的事件,直到完成將當前會話狀態存儲到Redis中,然後繼續處理接收到的事件,這就是爲什麼我需要阻止事件循環以讓這些事件排隊並防止競賽狀況。 – faressoft

+0

您可以在不阻塞主線程的情況下做到這一切。無論如何,你說任何建議,那是我的。如果這是一個多用戶網站,這樣做會削弱它。 – Keith

回答

1

你應該看看使用async/await。您必須重新編寫所有適用的代碼才能使用Promises,或使用爲您提供的庫。

您的主要功能可能看起來像這樣;

(async function main(){ 
try{ 

await taskFunction(); 
await backupGetFunction(); 
await backupSetFunction(); 
    res.send('I am done'); 

} catch (error){ 
    throw error; 
}; 

})(); 

一切都將按順序執行,最後,它會res.send'我完成'按預期。

該解決方案背後的複雜性是任何依賴主函數的函數都需要使用promise來保持流異步。

作爲一個例子,您的備份功能最初可能是;

function backupExample(){ 
fs.copyFile('source.txt', 'destination.txt', (err) => { 
    if (err) throw err; 
console.log('source.txt was copied to destination.txt'); 
}); 
}; 

當它必須轉換爲以下內容才能使用async/await;

async function backupExample(){ 
return new Promise((resolve, reject) => { 
fs.copyFile('source.txt', 'destination.txt', (err) => { 
    if (err) reject(err); 
resolve('source.txt was copied to destination.txt'); 
    }); 
}); 
}; 

該承諾充當主要異步/等待函數的指導,以便它知道異步函數何時完成。

+0

你能舉例說明如何在代碼中異步/等待? – egon12

+0

根據您的要求更新egon12。 – Edin

+0

我認爲'異步函數backUpExample'不需要'async'關鍵字,因爲它已經返回'Promise'。 – egon12

0

你可以使用。

redis.getAsync('backup') 
.then(res => { 

// ...... Do some changes to the backup data 
return redis.set('backup', backup) 
}) 
.then(()=>res.send('I\'m done')) 

let backup = await redis.getAsync('backup'); 
    // ...... Do some changes to the backup data 
    redis.set('backup', backup); 
    res.send('I\'m done'); 

注意:如果使用異步/等待你需要有至少節點V7和最多的功能。或者在運行節點時使用--harmony-async-await標誌

相關問題