JavaScript 通过队列实现异步流控制
2018-03-31 11:37
369 查看
知乎上面看到一个面试题。
某个应用模块由文本框 input,以及按钮 A,按钮 B 组成。点击按钮 A,会向地址 urlA 发出一个 ajax 请求,并将返回的字符串填充到 input 中(覆盖 input 中原有的数据),点击按钮 B,会向地址 urlB 发出一个 ajax 请求,并将返回的字符串填充到 input 中(覆盖 input 中原有的数据)。 当用户依次点击按钮 A、B 的时候,预期的效果是 input 依次被 urlA、urlB 返回的数据填充,但是由于到 urlA 的请求返回比较慢,导致 urlB 返回的数据被 urlA 返回的数据覆盖了,与用户预期的顺序不一致。 请问如何设计代码,解决这个问题?
作者:欲三更
链接:https://zhuanlan.zhihu.com/p/25259283
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
网上搜了一下,找到的答案我认为不是特别好。如果这个拓展一下,变成依次点击按钮ABCDEFG,或者是BAAB来回点,就不好做了。
知乎下面有人说用Rxjs不到十行代码,我没试过。不过这 个毕竟是框架,库。能够原生解决,还是能学不少东西的。
我认为这个场景明显是适合用队列的。当时在思考中我先用队列粗暴的实现一个同步阻塞发送ajax的程序。后面我感觉应该再优化升级,异步非阻塞发送ajax,实现这个需求。我把的思路过程写下来。
我们用setTimeout模拟ajax,通过队列记录点击顺序,然后通过promise依次执行ajax。前一个ajax执行玩之后,再执行后一个ajax。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="text"/> <button id="domA">A</button> <button id="domB">B</button> </body> <script> const domA = document.querySelector('#domA') const domB = document.querySelector('#domB') const input = document.querySelector('input'); //模拟ajax const ajaxA = () => new Promise((resolve, reject) => { setTimeout(() => { console.log('ajaxA end') input.value = 'ajaxA end'; resolve() }, 4000) }) const ajaxB = () => new Promise((resolve, reject) => { setTimeout(() => { console.log('ajaxB end') input.value = 'ajaxB end'; resolve() }, 1000) }) </script> <script> class Queue { constructor() { this.store = [] } enqueue(ele) { this.store.push(ele) } dequeue() { return this.store.shift(); } empty() { if (this.store.length === 0) return true; else return false; } } const events = new Queue(); let flag = false; const run = async () => { flag = true; while (!events.empty()) { await events.dequeue()(); } flag = false; } domA.addEventListener('click', () => { events.enqueue(ajaxA); if (!flag) { run() } }) domB.addEventListener('click', () => { events.enqueue(ajaxB); if (!flag) { run() } }) </script> </html>
依次点击ABBA
Okay。解决了。但是让我想再升级一下问题。面试官说你这是同步阻塞发的ajax。我要不阻塞,点击了按钮就发ajax,不要浪费时间去等待ajaxA完成了再发ajaxB。显示的顺序还是按点击的顺序先A后B。
我们改一下程序,我们再点击了按钮之后立刻执行ajax(),这里个函数返回的是promise,把这个promise存入队列。队列执行过程中,登待promise的状态为resolve之后立刻就改变input的值。
由于ajaxB都已就绪,所以input的值改变非常迅速,肉眼已经跟不上了。我们在控制台打印出来。可以清晰看到ajax和input改变的顺序。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="text"/> <button id="domA">A</button> <button id="domB">B</button> </body> <script> const domA = document.querySelector('#domA') const domB = document.querySelector('#domB') const input = document.querySelector('input'); //模拟ajax let value; const ajaxA = () =>new Promise((resolve, reject) => { setTimeout(() => { console.log('ajaxA end') resolve('ajaxA end') }, 4000) }) const ajaxB = () => new Promise((resolve, reject) =>{ setTimeout(() => { console.log('ajaxB end') resolve('ajaxB end') }, 1000) }) </script> <script> class Queue { constructor() { this.store = [] } enqueue(ele) { this.store.push(ele) } dequeue() { return this.store.shift(); } empty() { if (this.store.length === 0) return true; else return false; } } const events = new Queue(); let flag = false; const run = async () => { flag = true; while (!events.empty()) { let event = events.dequeue(); input.value=await event; console.log('input.value',input.value) } flag = false; } domA.addEventListener('click', () => { events.enqueue(ajaxA()); if (!flag) { run() } }) domB.addEventListener('click', () => { events.enqueue(ajaxB()); if (!flag) { run() } }) </script> </html>
依次点击ABBA
相关文章推荐
- javascript 通过模块模式实现代码访问控制
- 队列实现异步--通过redis
- 【javascript】Promise/A+ 规范简单实现 异步流程控制思想
- JavaScript中使用Async实现异步控制
- Javascript实现任务队列(异步)山寨版
- 实现对现有的aspx请求进行异步队列控制处理
- 通过JavaScript代码实现 标题的控制+添加信息
- javascript 通过ajax实现服务器异步数据操作
- 通过JS控制CSS实现连帧动画
- Javascript异步流程控制之Promise(1)-Angular $q简介
- JavaScript实现异步的机制
- 通过javascript实现点击一个按钮触发发音的动作
- Javascript使用定时器来处理数组和分割任务实现异步
- 一元多项式的乘法与加法运算【Java实现--通过单项链表实现队列】
- 通过API实现C#对硬件的控制(一)
- 使用JavaScript的数组实现数据结构中的队列与堆栈
- Javascript实现图片轮播效果(二)图片序列节点的控制实现
- Java通过两个栈实现队列
- javascript实现队列功能
- 自动化测试: 通过FF.au3 实现 AutoIt 控制 Firefox 浏览器