摘要:而这样一层一层嵌套进去的作用就是一个执行完了,执行下一个。函数的参数和函数一样,只不过是执行的顺序与函数相反,是倒过来执行的。第二个方案,也是他给我的思路。
这篇文章的起源是这样一段代码
这段代码的作用很简单,就是让一系列的动画,按顺序执行。而这样一层一层嵌套进去的作用就是一个执行完了,执行下一个。
为了解决这个问题我就想到了是不是可以把这些事件放到一个数组里,然后依次执行呢?也就是说实现一个seq(tasks,finally)函数
/** * @param {function []} tasks - function array * @param {function} cb - 执行完的回调 */ function seq(tasks, cb) { }
我的思路是每次执行完一个function之后再执行下一个函数,如果执行到最后一个函数就执行最后的cb即
function seq(tasks, cb) { (function runTask(i) { var task = tasks[i]; task(function() { i++; if (i !== tasks.length) { runTask(i); } else { cb(); } }); })(0); }
但是显然这么实现并不优雅(Zhuāng Bī),那么有没有更优雅的方案呢?显然是有的。我们可以使用ES5的reduceRight函数(MSDN文档)
如果你并不知道这个函数的话,我们就要从和它差不多的reduce函数(MSDN文档)说起了。
reduce函数接收两个参数callback、initialValue
callback
执行数组中每个值的函数,包含四个参数
previousValue
上一次调用回调返回的值,或者是提供的初始值(initialValue)
currentValue
数组中当前被处理的元素
index
当前元素在数组中的索引
array
调用 reduce 的数组
initialValue
作为第一次调用 callback 的第一个参数。
/** @examples **/ var array = [ { id: 1, name: "小李" }, { id: 2, name: "小张" }, { id: 3, name: "小刘" }, { id: 4, name: "小王" } ] var objMap = array.reduce(function(map,nowObj,index,array) { map[nowObj.id] = nowObj; return map; },{});
很简单的就把一个array,转成了一个以id为key,obj为value的ObjMap有木有?就是这么简单。
reduceRight函数的参数和reduce函数一样,只不过是执行的顺序与reduce函数相反,是倒过来执行的。这样的话我们就可以把上面那个tasks转换成类似最一开始那张图一样的结构。
function seq2(tasks, cb) { tasks.reduceRight(function(cb, task) { return function() { return task(cb); }; }, cb)(); } //这段代码的推导如下 //第一次执行 function() { return task5(cb); }; //第二次执行 function() { return task4(function() { return task5(cb); }); } //第三次执行 function() { return task3(function() { return task4(function() { return task5(cb); }); }); }; //第四次执行 function() { return task2(function() { return task3(function() { return task4(function() { return task5(cb); }); }); }) }; //最后一次执行 function() { return task1(function() { return task2(function() { return task3(function() { return task4(function() { return task5(cb); }); }); }); }); };
这样就得到了一个跟上面最一开始那张图一模一样的一个function,然后最重要的是reduceRight面那个(),他就是启动这个最终返回function的开关。
测试用例如下:
var tasks = [1, 2, 3, 4, 5]; tasks = tasks.map(function(i) { return function(cb) { setTimeout(function() { console.log(i); cb(); }, Math.random() * 500 | 0); } }); seq(tasks, function() { console.log("all Done"); }); seq2(tasks, function() { console.log("all Done"); });
这个问题是我公司的一位同事(老师)给我出的题目。第二个方案,也是他给我的思路。感谢我的这位老师,虽然在工作中我说的不多,但是在我内心里,我对您的崇拜那是简直了。哈哈。最后是github源代码
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/79611.html
摘要:并行和串行任务在里面异步是一个很重要的知识点的异步跟其他语言不一样他是根据执行回调的方式来实现的。在之前,执行任务想要实现这个流程控制只能通过依赖来实现或者通过而在之后官方自己实现了和来实现。 JavaScript 并行和串行任务 在 JavaScript 里面 异步 是一个很重要的知识点,JS 的异步跟其他语言不一样, 他是根据执行回调的方式来 实现的。由于我们不知道异步什么时候会...
摘要:相关环境由于是一个几年前的项目,所以使用的是这样的。一些小提示本次优化笔记,并不会有什么文件的展示。将异步改为了串行,丧失了作为异步事件流的优势。 这两天针对一个Node项目进行了一波代码层面的优化,从响应时间上看,是一次很显著的提升。 一个纯粹给客户端提供接口的服务,没有涉及到页面渲染相关。 背景 首先这个项目是一个几年前的项目了,期间一直在新增需求,导致代码逻辑变得也比较复杂,接...
摘要:所以这里需要另外的操作来对文件加载进行优化加载这是中定义的一个属性,它用来表示的是,当渲染引擎遇到的时候,如果引用的是外部资源,则会暂时挂起,并进行加载。 在js引擎部分,我们可以了解到,当渲染引擎解析到script标签时,会将控制权给JS引擎,如果script加载的是外部资源,则需要等待下载完后才能执行。 所以,在这里,我们可以对其进行很多优化工作。 放置在body底部 为了让渲染引...
摘要:前同事留下的测试,是基于浏览器的,主要还是功能测试。这里不详细说怎么在浏览器端使用测试了。而且作者也是建议和支持这样做的,简单明了的测试脚本,重要性有时候可能和测试本身一样重要。经测试,在浏览器也有这种问题。 2016-09-03 更新 随着在工作学习中更多地接触、使用测试工具,发现自己在本文中的一些记录是不准确、不正确的。 今天(九月三日)在家看了 NingJs 的直播,其中有一个分...
阅读 1240·2021-11-22 13:54
阅读 1425·2021-11-22 09:34
阅读 2698·2021-11-22 09:34
阅读 4008·2021-10-13 09:39
阅读 3342·2019-08-26 11:52
阅读 3361·2019-08-26 11:50
阅读 1529·2019-08-26 10:56
阅读 1913·2019-08-26 10:44