本文共 1972 字,大约阅读时间需要 6 分钟。
测试:有个查千万级的页面,查的特别慢导致页面都崩溃了,你们开发解决一下。
开发组:sql我们已经做优化了,它还是慢我们也没办法啊,优化我们都不会啊,新来的,要不你看一下?只要保证页面不崩就行。 我:嗯?好吧,刚来也没事干,就看一下吧。关于sql优化学习尚浅,只知道降低查询结果集的数据量来解决,比如分库分表、建索引、分页查询,还有最近刚学习的Oracle强大的分区表!同事说保证页面不会崩溃就行了。。。呃,好的。
只考虑IE和谷歌浏览器,IE没有页面无响应时的处理机制,而谷歌会在页面很长时间无响应后,就会触发,弹出“页面已经崩溃了”的提示。
由于查询是同步的,会阻塞主线程,导致系统所有页面都处于“不可响应”的状态。
了解了原因后,可以采用多线程和异步的方式来解决: 1、改成异步查询 2、采取多线程查询(需要考虑线程相关问题,比如:死锁、线程安全等) 异步比出现很多不必要的问题。异步不很简单么,ajax不就异步的么!
由于技术太古老以及专属框架,ajax无法应用上。。。网上说js的setTimeout函数就是异步的,然后我就将查询方法放到了该函数里,测试结果告诉我不行!!!思考一下:异步和同步、阻塞和非阻塞,排列组合的4种情况。
(知识尚浅,有不正确的情指正) 感觉异步也是一个主线程,可能会阻塞,也可能不阻塞。像一个网页中的元素图片、文字之类,页面加载完成之后,图片才会慢慢的异步加载出来,且不会阻塞用户的响应操作。这和H5的标签特性好像有关系,img标签的src属性好像就是异步加载的。异步好像行不通,那就研究多线程吧。
直接上代码,详细的用法讲解请参照
//引入外部大佬封装好的查询组件jsimportScripts('../common/EasyQueryVarxxx.js');//监听主线程传来的参数this.addEventListener('message',function(event){ var sql=event.data; var resultMsg=easyQueryVerxxx(sql); //大佬封装的公共查询函数,传入sql语句,直接返回结果 //把结果返回给主线程 this.postMessage(resultMsg); console.log('worker query end'); self.close();},false);
//开启子线程进行处理var worker = new Worker("./commonWorker.js");//向子线程传递参数worker.postMessage("select xxx,xxx,xx, from t_xxxx");//监听子线程发送回来的数据(回调函数)worker.onmessage = function (event){ var resultMsg=event.data; //已经在主线程中拿到结果了,然后正常处理就可以额 console.log(resultMsg);};
这是最简单的代码,要保证系统的可靠性,还需要做控制。假定子线程的查询需要2s的处理时间,由于后台发生了意外的情况,导致子线程2s后还没有返回,然后用户改变的查询条件又点击了一次,这时又一个线程去后台查询了,但这次没有意外,很快用户看到了结果,但由于上一个子线程正常返回了,用户就会看到结果后又被刷新为上一次的查询结果,或者其它未知的情况。
我负责的模块由于性能需要,根据查询条件来决定是否开启子线程去查询。
所以对代码稍作改造,加入一个共享变量来同步,就可以了。
//定义一个全局的同步变量var synchroFlag=0;--------------//每开启子线程去处理时synchroFlag=1;var worker = new Worker("./commonWorker.js");worker.postMessage("select xxx,xxx,xx, from t_xxxx");worker.onmessage = function (event){ var resultMsg=event.data; console.log(resultMsg); //释放 synchroFlag=1;};--------------//在查询中添加判断 if(synchroFlag>0){ alert("请稍等上一次查询结束后,再查询。"); return false; }
这样,就可以基本满足业务需要了。
转载地址:http://qbqmi.baihongyu.com/