众所周知,js是单线程的,没法保持多个函数同时运行。一直没有找到外部中断某函数运行的方法。
应用场景是:我有一个js 下棋的AI程序,AI在思考某一步棋的时间可能要花很长时间去计算(可能超过一两分钟),在这个计算过程中,整个页面都处于一个假死状态,用户点结束或退出按钮都不会有反应,造成很不好的用户体验。想找一个方法,AI在计算时,点个按钮就强行中止它的计算。一直没找到好的方法解决这个问题。
个人认为可以将演算部分交给后台解决,前台用Ajax调用,并设置超时时间。
var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { alert("ready state = 4"); } }; xhr.open("POST", "http://www.example.com", true); xhr.ontimeout = function () { alert("Timed out!!!"); } xhr.send(); btn.click = function() { xhr.timeout = 1000; }
不过没有验证过。
这种方式是可以中断,因为ajax可以异步执行。但是我的AI计算不能放到后台进行,因为计算量太大,如果多用户并发,后台服务器根本计算不过来。
@飞不动: 那可以考虑一下web worker,现代浏览器基本上都支持JS多线程了。
@逐影: 非常感谢,用web worker初步试验比较成功。不知web worker现在兼容性如何,手机上主流浏览器是否支持?
@飞不动:
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | Firefox OS (Gecko) | IE Phone | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|---|
Basic support(基础支持) | 4.4 | 4[1] | 3.5 | 1.0.1 | 10.0 | 11.5[1] | 5.1[2] |
Shared workers(共享worker) | 未实现 | 4[1] | 8 | 1.0.1 | 未实现 | 未实现 | 未实现 |
Passing data using structured cloning(使用结构化克隆传递数据) | 未实现 | 4 | 8 | 1.0.1 | 未实现 | 未实现 | 未实现 |
Passing data using transferable objects(使用可转让对象传递数据) | 未实现 | 未实现 | 18 | 1.0.1 | 未实现 | 未实现 | 未实现 |
这个场景,使用ServiceWorker来进行高负载运行,然后再每次循环的是时候,判断下终止变量。通过外部发消息给ServiceWorker,来设置终止变量。
// 大致思路如下 var isStop = false; function run(){ if(!isStop){ while(){} // 高负载任务,注意,把长期的任务分解下。 } setTimeout(()=>fun()); // 通过延迟执行,才能让引擎接收外部消息 } run();
刚了解了一下ServiceWorker,该功能似乎支持的浏览器不多,并且还是试用阶段,不太敢用到产品中去。
web worker倒是一个比较好的思路,以前对这方面了解得很少。初步了解它不能跟dom交互,估计要用它我的程序也要做比较大的改动,我准备做一些偿试。
两位的回答对我都很有帮助,开阔了我的思路。非常感谢!
@飞不动: 抱歉,有些误导。ServiceWorker是基于WebWorker,针对缓存功能的。多余多线程,还是应该使用WebWorker。至于和dom交互,需要通过消息通知,让主线程进行dom操作。