競態(tài)條件Race condition及如何避免的三種方案詳解
什么是競態(tài)條件?
當(dāng)你的程序依賴正確的響應(yīng)順序,但響應(yīng)的順序又無法保證時(shí),可能會(huì)導(dǎo)致意外的結(jié)果,這就是競態(tài)條件。
舉個(gè)用戶界面的例子:
在上圖中,分別點(diǎn)擊科技和生活tab時(shí),期望能夠展示對應(yīng)的數(shù)據(jù)。
我們來設(shè)想如下情況:
- 點(diǎn)擊科技按鈕(高亮科技按鈕)(數(shù)據(jù)2秒后返回)
- 點(diǎn)擊生活按鈕(高亮生活按鈕)(數(shù)據(jù)1秒后返回)
最終,展示區(qū)域會(huì)在1秒后顯示生活數(shù)據(jù),2秒后展示科技數(shù)據(jù),但此時(shí),我們的按鈕會(huì)高亮?xí)谏钌希覀兊恼故緟^(qū)域顯示的卻是科技數(shù)據(jù)。也就是高亮的按鈕和展示數(shù)據(jù)不同步,這就是競態(tài)條件造成的問題。
如何避免?
方案1:每次操作完成之前,阻止新的操作
這個(gè)方案用的比較普遍,具體思路就是請求發(fā)生期間,添加一個(gè)loading遮罩層,這樣在當(dāng)前請求響應(yīng)之前,后續(xù)的操作都會(huì)被loading遮罩層避免掉,也就不會(huì)有競態(tài)問題的發(fā)生。
方案2:每次發(fā)送請求時(shí),丟掉上一個(gè)請求的響應(yīng)
該方案的思路是,在響應(yīng)完成之前,如果用戶有新的請求,那就丟棄掉未完成的請求,其結(jié)果就是只對最新的請求進(jìn)行響應(yīng),也就避免出現(xiàn)舊的請求響應(yīng)數(shù)據(jù)展示在了當(dāng)前高亮視圖下。
function getResolveWhenLast() { let globalId = 0; return (pro) => { return new Promise((resolve, reject) => { const id = ++globalId; pro .then((res) => { if (id === globalId) { resolve(res); } }) .catch(err => { if (id === globalId) { reject(err); } }) }) } } const resolveWhenLast = getResolveWhenLast() // 使用resolveWhenLast包住你的請求,就可以解決競態(tài)問題 resolveWhenLast(api.getPosts()).then(res => { // ... })
方案3:每次發(fā)送請求時(shí),取消掉上一次的請求
給promise加了一層包裝,添加了cancel的能力,每次請求發(fā)出的時(shí)候,將上一次的請求取消掉,同樣達(dá)到了只最處理最新一次請求響應(yīng)的目的,也就避免了競態(tài)條件的發(fā)生。
// 給Promise添加取消請求的能力 function createImpretivePromise(pro) { let resolve = null; let reject = null; const warppedPromise = new Promise((_resolve, _reject) => { resolve = _resolve; reject = _reject; }) pro .then((res) => { resolve && resolve(res); }) .catch((err) => { reject && reject(err); }); // 可以切斷代理 const cancel = () => { resolve = null; reject = null; } return { promise: warppedPromise, cancel } } const getResolveWhenLast = () => { let globalCancel = null; return (pro) => { const { promise, cancel } = createImperativePromise(pro); globalCancel && globalCancel(); globalCancel = cancel; return promise; }; }; const resolveWhenLast = getResolveWhenLast() // 使用resolveWhenLast包住你的請求,就可以解決競態(tài)問題 resolveWhenLast(api.getPosts()).then((res) => { // ... });
以上就是競態(tài)條件Race condition及如何避免的三種方案詳解的詳細(xì)內(nèi)容,更多關(guān)于競態(tài)條件 Race condition的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
ECMAScript 6數(shù)值擴(kuò)展實(shí)例詳解
這篇文章主要為大家介紹了ECMAScript6數(shù)值擴(kuò)展實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08ComponentLoader?與動(dòng)態(tài)組件實(shí)例詳解
這篇文章主要為大家介紹了ComponentLoader?與動(dòng)態(tài)組件實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05JavaScript前端學(xué)算法題解LeetCode最大重復(fù)子字符串
這篇文章主要為大家介紹了JavaScript前端學(xué)算法題解LeetCode最大重復(fù)子字符串,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09使用compose函數(shù)優(yōu)化代碼提高可讀性及擴(kuò)展性
這篇文章主要為大家介紹了使用compose函數(shù)提高代碼可讀性及擴(kuò)展性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06