前言

在日常开发中,也许我们会遇到这样的一个问题。我们利用【发布订阅模式】(如果不了解的可以直接访问此链接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. DAO与DTO

    DAO叫数据访问对象(data access object) DTO是数据传输对象(data transfer object) DAO通常是将非对象数据(如关系数据库中的数据)以对象的方式操纵.(即一 ...

  2. [Unity]Unity3D编辑器插件扩展和组件扩展

    1. 插件扩展 1.1. 命名空间 using UnityEditor; using UnityEngine; //非必需,常用到 1.2. 使用语法 [MenuItem("Assets/M ...

  3. tomcat 内存大小配置

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个java虚拟机.JAVA程序启动时JVM都会分配一个初始内存和最大内存给这个应用程序.这个初始内存和最大内存在一定程度都会 ...

  4. ViewPager使用记录1——展示固定数据

    ViewPager是v4支持库中的一个控件,相信几乎所有接触Android开发的人都对它不陌生.之所以还要在这里翻旧账,是因为我在最近的项目中有多个需求用到了它,觉得自己对它的认识不够深刻.我计划从最 ...

  5. 我的第一个python web开发框架(8)——项目结构与RESTful接口风格说明

    PS:再次说明一下,原本不想写的太啰嗦的,可之前那个系列发布后发现,好多朋友都想马上拿到代码立即能上手开发自己的项目,对代码结构.基础常识.分类目录与文件功能结构.常用函数......等等什么都不懂, ...

  6. 中秋H5,这篇脑洞开的可以!

    案例:嫦娥--寻开心出品:凯迪仕 1.内容:这是一支视频类H5案例.Loading完毕进入页面,首屏提示案例最佳观看方式为先锁屏再横屏.点击开始按钮播放视频,视频讲述"葫芦娃"缠着 ...

  7. 使用Xshell5连接虚拟机VMware中安装的CentOS7系统

    使用Xshell5连接VMware中安装的CentOS7系统 准备材料 Xshell 下载地址 VMware Workstation 12 Pro 下载地址 CentOS 7 64位系统 下载地址 安 ...

  8. Thinking in React Implemented by Reagent

    前言  本文是学习Thinking in React这一章后的记录,并且用Reagent实现其中的示例. 概要 构造恰当的数据结构 从静态非交互版本开始 追加交互代码 一.构造恰当的数据结构 Sinc ...

  9. web容器启动后自动执行程序的几种方式比较

    1.       背景 1.1.       背景介绍 在web项目中我们有时会遇到这种需求,在web项目启动后需要开启线程去完成一些重要的工作,例如:往数据库中初始化一些数据,开启线程,初始化消息队 ...

  10. 深入理解Java虚拟机--下

    深入理解Java虚拟机--下 参考:https://www.zybuluo.com/jewes/note/57352 第10章 早期(编译期)优化 10.1 概述 Java语言的"编译期&q ...