🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
事件队列的基本原理 ``` //eventLoop ->事件队列,由外部push var eventLoop = []; var event while(true) { //一次tick if(eventLoop.length > 0) { event = eventLoop.shift(); try { event() } catch(err) { reportError(err); } } } ``` javascript是单线程的,函数具有原子性,一旦foo或bar开始运行,bar或foo的任意一行代码都必须在前一个函数执行后才会执行,也就是说异步的结果只有两种可能 ``` a = 1, b = 2; foo = () => {a++; b = a + b;} bar = () => {a--; b = a - b} ajax(url, foo) ajax(url, bar) ``` onscroll事件发送ajax请求并处理响应,js是单线程,一次只能一个事件,要么是onscroll执行发送请求,要么是处理请求 ``` onscroll,请求1 onscroll,请求2 响应1 onscroll,请求3 响应2 响应3 ``` 如果结果值依赖于两个请求的结果,可以这样 ``` var res = []; function responese(data) { if(data.name = 'qc') res[0] = data; else if(data.name = 'sunny') res[1] = data; } //假设aurl返回data的name为qc,burl为sunny ajax('aurl', response); ajax('burl', response); //这样一来,无论谁先返回请求,res的结果都不受影响 ``` ``` var a, b; function foo(x) { a = x * 2; baz();} function bar(y) {b = y * 2; baz();} function baz() {console.log(a + b);} ajax('aurl', foo); ajax('burl', bar); //无论谁先返回请求,baz在执行console时都会报错,因此此时要么没有a要么没有b function foo(x) { a = x * 2; a && b && baz();} function bar(y) {b = y * 2; a && b && baz();} //先返回请求的一定不会执行baz,但此时的a或b已经赋值成功,后返回请求的一定执行baz //我们称a && b为门,只有a、b都准备好后,才把门打开(baz()) ``` 批处理 ``` var res = []; function response(data) { res = res.concat(data.map(val => val * 2)); } ajax('aulr', response); ajax('bulr', response); //之前说了,一个函数在执行时另一个函数只能等待。假设a响应先返回,但a的数据量很大很大,那么b回来后只能等待a执行完后才执行,此时页面上的其他代码都不会执行 ``` ``` function response(data) { //一次只处理1000个 var chunk = data.splice(0, 1000); res = res.concat(chunk.map(val => val * 2)); //还有要处理的吗 //利用setTimeout将剩下的放在事件队列最后,保证另一个响应的函数先执行 //代价就是会产生很多的后续进程 if(data.length > 0) {setTimeout(() => response(data))} } ```