异步函数顺序执行的实现
2017-03-24 20:21
288 查看
这几天在研究实现一个类似Promise思想的库,也不完全一样,主要目标是保证异步事件的执行顺序。
比如有四个异步事件A,B,C,D
需要这样一个执行顺序 A => B => C => D
想了好几种方案。
其中有一种是先建立一个任务链表,执行时修改每个事件的函数内容。
假设现在任务链表顺序已经建立, A => B => C => D。
并且四个函数大概是这样:
还有一个修改函数的函数inject,这个函数执行时可以修改前面四个函数的内容。
首先,这个inject函数这样写:
1.先加载fn参数的内容:
以函数D为例,得到source的值就是函数D的定义:
2.给source注入一句执行链表中下一个函数的代码。
这里我想了个办法,先去掉source中
这样,根据我们注入的代码,执行完inject(D),就会把D函数的内容shift掉,使链表中紧跟D函数的函数成为链表中的第一个函数,从而执行
同理,如果A,B,C,D四个函数都是同步的,那么只需要inject这一个函数就可以让他们按顺序执行。
来考虑异步的A,B,C函数,我们依葫芦画瓢,用inject函数的思想,来重写一下A函数中调用的setTimeout方法。
如此,把调用下一个函数的方法放在定时器内,就完成了对setTimeout的重写。
我们把所有的代码放在一起测试一下
https://html50.github.io/chain.js/test1.html
可以看出,A,B,C,D依次输出了。
在上面的基础上,我们使用构造函数的方法,把代码重新整理一下(结构)。
再写几个异步的函数用于测试
测试
完整代码测试页面:
https://html50.github.io/chain.js/test2.html
这样算是基本的功能完成了。根据我的测试,如果要应用到具体的工作中,还是使用PROMISE比较靠谱。而且我写的这个函数对于ajax setTimeout的操作不够灵活,不可以嵌套,不可以混合使用。但是这些都是可以改进的,即进行更深的匹配修改。实现的本身也可以当做一种不同的思路吧。
一个异步读取图片并展示的DEMO:
https://html50.github.io/chain.js/
比如有四个异步事件A,B,C,D
需要这样一个执行顺序 A => B => C => D
想了好几种方案。
其中有一种是先建立一个任务链表,执行时修改每个事件的函数内容。
假设现在任务链表顺序已经建立, A => B => C => D。
taskList[function A,function B,function C,function D]
并且四个函数大概是这样:
function A(){ setTimeout(function(){ output.innerText+='第一个异步函数,延迟1秒执行\n'; },1000); } function B(){ setTimeout(function(){ output.innerText+='第二个异步函数,延迟2秒执行\n'; },2000); } function C(){ setTimeout(function(){ output.innerText+='第三个异步函数,延迟3秒执行\n'; },3000); } //D函数是个普通函数 function D(){ output.innerText+='第四个普通函数,无延迟,立即执行\n'; }
还有一个修改函数的函数inject,这个函数执行时可以修改前面四个函数的内容。
function inject(fn){ //对每一个传入的fn进行修改,然后才能执行 }
首先,这个inject函数这样写:
1.先加载fn参数的内容:
function inject(fn){ var source = fn.toString(); }
以函数D为例,得到source的值就是函数D的定义:
inject(D); //source的值 function D(){ output.innerText+='第四个普通函数,无延迟,立即执行\n'; }
2.给source注入一句执行链表中下一个函数的代码。
这里我想了个办法,先去掉source中
function (){和
},留下的就是函数体的内容。然后在函数体的最后,加上我想要的代码:
function inject(fn){ var source = fn.toString(); var startPos = source.indexOf('{') + 2, endPos = source.lastIndexOf('}') -1; //{ 和 }的位置 //+2是加上{本身和换行的位置 //-1是减去换行的位置 source = source.substring(StartPos,endPos); //截取出来函数体 alert('第一个函数'); source += "taskList.shift();taskList[0]();"; //写入自定义代码到函数体,链表taskList将首项shift掉,这样把第二个函数移到了第一位,然后再执行。 //使用eval执行修改后的函数体 try{ eval(source); } catch(err){ alert(err); } }
这样,根据我们注入的代码,执行完inject(D),就会把D函数的内容shift掉,使链表中紧跟D函数的函数成为链表中的第一个函数,从而执行
taskList[0],完成链表的顺序执行。
同理,如果A,B,C,D四个函数都是同步的,那么只需要inject这一个函数就可以让他们按顺序执行。
来考虑异步的A,B,C函数,我们依葫芦画瓢,用inject函数的思想,来重写一下A函数中调用的setTimeout方法。
var _setTimeout = setTimeout, setTimeout = function(fn,time){ var source = fn.toString(), startPos = source.indexOf('{') + 2, endPos = source.lastIndexOf('}') -1; source = source.substring(startPos,endPos) + "taskList.shift();taskList[0]();"; try{ _setTimeout(function(){eval(source)},time); } catch(err){ alert(err); } }
如此,把调用下一个函数的方法放在定时器内,就完成了对setTimeout的重写。
我们把所有的代码放在一起测试一下
https://html50.github.io/chain.js/test1.html
可以看出,A,B,C,D依次输出了。
在上面的基础上,我们使用构造函数的方法,把代码重新整理一下(结构)。
function Chain(){ this.taskList = [], this.errorList = [], this.successList = [], this.length = arguments.length; for (i = 0; i < this.length; i++) { this.taskList.push(arguments[i]); } this.next = function() { if (this.taskList.length > 0){ this.inject(this.taskList[0]); } else output.innerText += '任务全部完成'; } this.start = function() { this.next(); } this.setTimeout = function(fn, time) { //处理setTimeout } this.ajax = function() { //处理ajax } }
再写几个异步的函数用于测试
function A() { setTimeout("output.innerText += '第一个异步函数,延迟1秒执行\\n'", 1000); } function B() { output.innerText += '第二个普通函数,无延迟,立即执行\n'; } function C() { setTimeout(function() { output.innerText += '第三个异步函数,延迟1秒执行\n'; }, 1000); } function D(text) { output.innerText += '第四个普通函数,自定义文字:' + text + ',无延迟,立即执行\n'; } function E() { ajax({ url: "test2.html", beforeSend:function(){ output.innerText += '第五个异步ajax函数,读取本页源码\n'; }, success: function(){ output.innerText += '读取完成,执行下一个函数\n'; } }) } function F() { setTimeout(function() { output.innerText += '第六个异步函数,延迟1秒执行\n'; }, 1000); }
测试
var job = new Chain(A, B, C, function a(){ D('函数传参'); }, E, F); job.start();
完整代码测试页面:
https://html50.github.io/chain.js/test2.html
这样算是基本的功能完成了。根据我的测试,如果要应用到具体的工作中,还是使用PROMISE比较靠谱。而且我写的这个函数对于ajax setTimeout的操作不够灵活,不可以嵌套,不可以混合使用。但是这些都是可以改进的,即进行更深的匹配修改。实现的本身也可以当做一种不同的思路吧。
一个异步读取图片并展示的DEMO:
https://html50.github.io/chain.js/
相关文章推荐
- 详解如何构建Promise队列实现异步函数顺序执行
- js 异步操作,回调函数控制执行顺序
- Jquery源码解析---利用队列来实现函数的顺序执行
- 模仿TMALL搜索,下拉提示 优化 用户keypress停顿200毫秒间隔时,在执行异步取数据操作 通过underscore的函数debounce来实现
- LazyMay:实现同步和异步任务的顺序执行
- js中的for循环与异步回调函数执行顺序问题
- 按顺序执行多个异步函数的方法
- async.js 实现js函数执行顺序
- ajax回调函数执行顺序带来的同步异步问题
- . 有一个一维数组,里面存储整形数据,请写一个函数,将他们按从大到小的顺序排列,要求执行效率高,并说明如何改善执行效率(该函数必须自己实现,不能使用php函数)。
- javascript 实现多个异步函数的同时执行后再执行回调函数
- ajax 如何用then 链式操作 实现异步先后执行顺序
- Promise 异步函数顺序执行
- 有a、b、c、d 4个异步请求,如何判断a、b、c、d都完成执行?如果需要a、b、c、d顺序执行,该如何实现?
- 如何按照顺序执行异步ajax的回调函数
- ajax回调函数执行顺序带来的同步异步问题
- ajax回调函数执行顺序带来的同步异步问题
- 异步函数的书写:使其可以按顺序执行
- 函数参数执行的顺序
- [Oracle DB管理] 通过数据库的锁实现Java中DML的顺序批次执行