前言

在日常开发中,也许我们会遇到这样的一个问题。我们利用【发布订阅模式】(如果不了解的可以直接访问此链接www.cnblogs.com/xiaoxiaokun… )去执行【发布】事件时,遇到函数内部涉及到异步执行时,就比较难以处理。为了满足这种需求,我专门写了一个这样的插件用于函数整合队列并顺序执行。

函数队列循环执行

/**
*1.0.0.1版本
*/
var list=[];//存储函数
list.push(function(){
console.log(1);
});
list.push(function(){
console.log(2);
});
list.push(function(){
console.log(3);
});
for (var i=0;fn=list[i++];) {
fn();//执行
}

结果:1,2,3
这是最简单的方式,可以实现函数整合成一个队列,按照先进先出顺序执行。现在在仔细看发现,如果函数中有异步执行那函数执行就不能保证按照顺序执行,例如:

var list=[];//存储函数
list.push(function(){
console.log(1);
});
list.push(function(){
setTimeout(function() {
console.log(2);
}, 2000);
});
list.push(function(){
console.log(3);
});
for (var i=0;fn=list[i++];) {
fn();//执行
}

输出的结果肯定是 1,3,2

/**
*1.0.0.2版本
*/
var list=[];
list.push(function(){
console.log(1);
});
list.push(function(){
console.log(2);
});
list.push(function(){
console.log(3);
}); function start(list){
if(list.length){
list.shift()();
arguments.callee(list);
}
}
start(list);

这种方式可以等到执行完毕,清除list内部执行过后的函数。不影响下次push 执行。但是异步函数还是未解决。

/**
*1.0.0.3版本
*/
var list=[];//存储数组的集合
list.push(function(){
console.log(1);
});
list.push(function(callback){
//callback是代表这个函数是异步的函数
setTimeout(function() {
console.log(2);
callback();//执行完异步函数执行回调函数
}, 2000);
});
list.push(function(){
console.log(3);
}); function start(){
//判断数组的长度
if(list.length){
var fn=list.shift();//取出数组第一个函数
//判断函数是否带有参数
if(fn.length){
fn(start);//执行该函数,并且把 start本身传递进去。
}else{
fn();
start();
}
}
}
start();

此版本可以解决带有异步执行的函数按照刚开始push进去的顺序依次执行。
需要注意的是,如果函数是内部带有异步执行的函数,需要传递一个参数来告诉start。但是如果我们push进去的函数本身有好多个参数这需要怎么办呢!!接下来看另一版本。

/**
*1.0.0.4版本
*/
var list=[];//存储数组的集合
list.push(function(){
console.log(1);
});
list.push(function(callback){
setTimeout(function() {
console.log(2);
callback();
}, 2000);
});
list.push(function(){
console.log(3);
}); function start(){
//判断数组的长度
if(list.length){
var fn=list.shift();//取出数组第一个函数
//判断函数是否带有参数
if(fn.length && getfunarg(fn)[0]=='callback'){
fn(start);//执行该函数,并且把 start本身传递进去。
}else{
fn();
start();
}
}
}
start();
/**
* 查找函数参数名
* @fn {Function } 要查找的函数
* @return []返回参数数组
* */
function getfunarg(fn) {
var f = /^[\s\(]*function[^(]*\(\s*([^)]*?)\s*\)/.exec(fn.toString());
return f && f[1] ? f[1].split(/,\s*/) : [];
}

到现在为止,我们这几个函数基本已经满足我们的需求,但是push的时候,假设函数多个参数,我们还需进一步优化代码!为了把这个插件做的更好。我决定还是把callback放在最后,这样就能保证函数传递参数不受影响。

最终版本

/**
* 作者:小小坤
* 联系:java-script@qq.com
* 日期:2017-11-11
* 版本:1.0.0.4
* -----------使用说明----------
* 1、把所有函数【包含异步执行的函数】按照顺序依次 使用lk.push存入
* 2、带有参数的函数,一定要注意{最一个参数如果是callback}会被认为是 异步执行函数
* 3、异步执行的函数,需要把最一个参数设置为callback。并在函数执行完毕执行callback();函数保证按照顺序执行
*
* */
;! function() {
var list = [], //存储函数的列表
isFun = Object.prototype.toString; //用于验证是否是函数
/**
* 添加到列表中
* @fn {Function} 函数体
* */
function push(fn) {
isFun.call(fn) === "[object Function]" && list.push(fn);
};
/**
* 开始执行列表中的所有函数,
* 按照先进先出原则
*
* */
function star() {
if(list.length) {
var fn = list.shift(),//截取第一个函数
arry=getfunarg(fn),//获取这个函数的参数列表
_length=arry.length;//参数列表的长度
if(_length && arry[_length-1] === 'callback') {
if(_length===1){
fn(star);
}else{
arry.pop();//删除最后一个参数
arry.push(star);//把回调函数存入数组
fn.apply(this,arry);
}
} else {
fn.apply(this,arry);
star();
}
}
}
/**
* 查找函数参数名
* @fn {Function } 要查找的函数
* @return []返回参数数组
* */
function getfunarg(fn) {
var f = /^[\s\(]*function[^(]*\(\s*([^)]*?)\s*\)/.exec(fn.toString());
return f && f[1] ? f[1].split(/,\s*/) : [];
}
//挂在到Windows上。
window.lk = {
push: push,
start: star
}
}();
//使用测试
/**--------一条华丽的分割线--------**/
var a=100,
b=200,
d=300,
f=400; //定义函数 a2 ,此函数带有一个参数,被认为是异步函数
function a2(a,b,callback) {
console.time('2');
setTimeout(function() {
console.timeEnd('2');
callback();
console.log(a,'a');
}, 1000);
}
//把函数函数 a2 放入数组
lk.push(a2); //定义函数 a3
function a3(d, f) {
console.log(f,'f');
console.log(3);
}
//把函数函数 a3 放入数组
lk.push(a3); //定义函数 a4 此函数带有一个参数,被认为是异步函数
function a4(callback) {
console.time('4');
setTimeout(function() {
console.timeEnd('4');
callback();
}, 2000);
}
//把函数函数 a4 放入数组
lk.push(a4); //最后开始执行
lk.start();

最终此插件完成,需要压缩的同学可以自行压缩。代码比较简单,提供了两个方法。
push存储函数列表
start开始执行

总结

通过上边的代码编写我们学到了处理函数列表时候,需要考虑到异步函数。处理异步函数,需要回调函数参与。这样就能帮助代码按照顺序执行。

js函数整合队列顺序执行插件的更多相关文章

  1. js函数和变量的执行顺序【易错】

    js函数和变量的声明与执行顺序 一.函数执行顺序 1.正常顺序 function f(){ alert(2); } f(); //alert 2 所有浏览器都能测试通过. 2.倒序调用 f(); // ...

  2. 【原创】cs+html+js+css模式(七): 顺序执行与并发执行问题,IIS7及其以上版本的抛错问题解决

          在进行开发的过程中,针对于这种模式,我们继承的IRequiresSessionState,这种对于我们的同一个IIS的执行中是顺序执行即一个ajax请求处理完成后,才能执行下一个ajax, ...

  3. js函数的解析与执行过程

    function f(a,b,c){ alert(a);//函数字符串 alert(b); var b = 5; function a(){ } } f(1,2); //预处理 lexicalEnvi ...

  4. 在JS函数中执行C#中的函数、字段

    1.调用字段 cs文件的代码: ; protected void Page_Load(object sender, EventArgs e) { id = ; } js页面的代码: function ...

  5. 各种常用js函数实现

    1.bind function bind(fn, context) {    var args = Array.prototype.slice.call(arguments, 2);    retur ...

  6. 如何编写高质量的 JS 函数(1) -- 敲山震虎篇

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm7Xi7JxQ作者:杨昆 一千个读者,有一千个哈姆雷特. 此系列文 ...

  7. jquery和js的几种页面加载函数的方法以及执行顺序

    参考博客:http://www.cnblogs.com/itslives-com/p/4646790.html    https://www.cnblogs.com/james641/p/783837 ...

  8. js函数和变量的声明与执行顺序

    一.函数执行顺序 1.正常顺序 function f(){ alert(2); } f(); //alert 2 所有浏览器都能测试通过. 2.倒序调用 f(); //alert 2 function ...

  9. js的并行加载以及顺序执行

    重新温习了下这段内容,发现各个浏览器的兼容性真的是搞大了头,处理起来很是麻烦. 现在现总结下并行加载多个js的方法: 1,对于动态createElement('script')的方式,对所有浏览器都是 ...

随机推荐

  1. 在前端页面对easyui中的datagrid与jqgrid加载后的数据进行操作

    因为项目的需求,需要在grid中加载数据后再在前端页面执行操作,所以在easyui中的grid与jqgrid都进行了测试和操作: eayui中grid数据的操作: //构造集合对象 var list ...

  2. IDEA Maven 三层架构 1、基本的Archetype 搭建

    JDK:1.8 Maven:3.3.9 三层架构:基于 SpringMVC 的 UI 层.业务逻辑层以及数据访问层 从对 Maven 的了解可以看出,三层架构的创建在于对文件夹的合理安排,他们通常是主 ...

  3. java四大会话技术

    未经作者允许,不得转载 第一cookie技术 常用方法: new Cookie(),构造一个cookie getName() ,获取cookie的名字 getValue () ,取到具体cookie的 ...

  4. 使用 Prometheus + Grafana 对 Kubernetes 进行性能监控的实践

    1 什么是 Kubernetes? Kubernetes 是 Google 开源的容器集群管理系统,其管理操作包括部署,调度和节点集群间扩展等. 如下图所示为目前 Kubernetes 的架构图,由 ...

  5. 【转】漫谈linux文件IO--io流程讲的很清楚

    [转]漫谈linux文件IO--io流程讲的很清楚 这篇文章写的比较全面,也浅显易懂,备份下.转载自:http://blog.chinaunix.net/uid-27105712-id-3270102 ...

  6. netbeans 字体发虚

    今天更新了netbeans,重启后蛋疼了,字体发虚,搜索网络后有得到如下方案: 对Archlinux,去/usr/share/netbeans/etc,里面找到netbeans.conf,给下面一行参 ...

  7. [Linux 使用(1)] SUSE Linux Enterprise Server 下虚拟机ip设置

    1.找到需要设置的地方 2.设置静态ip 下一步 3.编辑DNS 4.设置默认网关 5.查看ip 6.本机测试是否能够ping通

  8. 微信退款流程,以及在过程中遇见的错误和解决方式(php 语言)

    官方下载demo 1:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1 开发步骤  :    https://pay.weix ...

  9. PHP基础入门详解(一)【世界上最好用的编程语言】

       简介 --------- PHP(超文本预处器)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域.PHP 独特的语法混合了C.Ja ...

  10. LINUX环境下SVN安装与配置(利用钩子同步开发环境与测试环境)

    安装采用YUM一键安装: 1.环境Centos 6.6 2.安装svnyum -y install subversion 3.配置 建立版本库目录mkdir /www/svndata svnserve ...