随着项目的推进,越来越多的需要在帧与帧之间写一些pause&continue的任务,写了几个后,觉得还是要从框架上来解决这个问题比较好。比如你需要渲染一个很大很大的表格。而表格单元里的内容和大小是是先不知道的,每一个表格的里单元渲染完毕都有可能直接引发整体的重新布局,这个消耗是非常大的,因此渲染和布局的任务不能一次性完成,就像加载页面的浏览器,如果在页面载入的时候不能进行任何操作,估计没有人能够忍受。
分时调度的基本思想是把原本一份执行过程切分成N分,一次执行一份或几份,如果在本帧内执行不完,就留到下一帧执行,直到全部执行完毕。这样保证前端的流畅度并且能完成任务,此外,如果有多个任务在执行的话,就存在调度的问题,不然大家就会撞车,结果还是跟不分开执行没什么么区别。 这时候,要是用python,ruby,或lua这样的软件来写程序就爽死了,直接在方法中放入yield。要做的事情是最少的。go的话,据说有coroutine,应该也不错。不支持yield的程序语言,有的人肯定想到了用线程……如果要用线程,权衡下由之引发的问题,宁可寻找一种不那么直接的处理方法。 接口设计: function add(type:int,tasks:Array,callback:function) type决定了一个此tasks的运行方式,基本类型有 1.顺次执行 假设一个任务的流程是 function foo(){ //do something1 //do something2 //do something3 return result } 改写成 function foo(callback){ function do1(){ //do something1 } function do2(){ //do something2 } function do3(){ //do something3 } function getresult(){ callback(result) } add(1,[do1,do2,do3],getresult) } 2.链形 链形每次返回下次执行的方法,直到返回null结束,比如for循环 function foo(){ for(i=0;i<10;i++){ //do something1 } } 改写后变成 function foo(callback){ i = 0; function doNext(){ //do something1 i++; if(i<10){ return doNext; }else{ callback(); return null; } } add(2,[doNext],null); } 可以选择将callback交给调度器返回,也可自行返回,自由决定。 调度主循环 function startLoop(){ timeleft = 0; onExitFrame(){ timeleft = getTime(); } onEnterFrame(){ timeleft = 1000/30-(timeleft-getTime());//比较两个差值记录本帧剩余时间量。假设一秒钟运行30帧 if(timeleft<=0){ //即使帧内时间已耗尽,至少执行一次 return; } while(timeleft){ time = getTime(); //遍历每个任务,执行 timeleft -= getTime()-time;//减去执行任务的损耗 }, } } 差不多了,其实还可以加上优先级别,再加上挂起,中断等方法,这就是个线程框架了,实施代码要多些。 虽然没有yield,但是人工的将代码分割,也并不是那么复杂的。