竞态条件Race condition及如何避免的三种方案详解
作者:热饭班长
这篇文章主要为大家介绍了竞态条件Race condition及如何避免的三种方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
什么是竞态条件?
当你的程序依赖正确的响应顺序,但响应的顺序又无法保证时,可能会导致意外的结果,这就是竞态条件。
举个用户界面的例子:
在上图中,分别点击科技和生活tab时,期望能够展示对应的数据。
我们来设想如下情况:
- 点击科技按钮(高亮科技按钮)(数据2秒后返回)
- 点击生活按钮(高亮生活按钮)(数据1秒后返回)
最终,展示区域会在1秒后显示生活数据,2秒后展示科技数据,但此时,我们的按钮会高亮会在生活上,但我们的展示区域显示的却是科技数据。也就是高亮的按钮和展示数据不同步,这就是竞态条件造成的问题。
如何避免?
方案1:每次操作完成之前,阻止新的操作
这个方案用的比较普遍,具体思路就是请求发生期间,添加一个loading遮罩层,这样在当前请求响应之前,后续的操作都会被loading遮罩层避免掉,也就不会有竞态问题的发生。
方案2:每次发送请求时,丢掉上一个请求的响应
该方案的思路是,在响应完成之前,如果用户有新的请求,那就丢弃掉未完成的请求,其结果就是只对最新的请求进行响应,也就避免出现旧的请求响应数据展示在了当前高亮视图下。
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包住你的请求,就可以解决竞态问题 resolveWhenLast(api.getPosts()).then(res => { // ... })
方案3:每次发送请求时,取消掉上一次的请求
给promise加了一层包装,添加了cancel的能力,每次请求发出的时候,将上一次的请求取消掉,同样达到了只最处理最新一次请求响应的目的,也就避免了竞态条件的发生。
// 给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包住你的请求,就可以解决竞态问题 resolveWhenLast(api.getPosts()).then((res) => { // ... });
以上就是竞态条件Race condition及如何避免的三种方案详解的详细内容,更多关于竞态条件 Race condition的资料请关注脚本之家其它相关文章!