这里我们来看看一种更给力的解决方案。 如果一个业务环节中需要对大数据集进行迭代处理,而这个数据集从开始迭代起,数据量不会再改变, 那麼可以考虑採用一种名为 duff 装置的技术。这项技术是以其的创造者 tom duff 的名字来命名的, 这项技术最先实现於 c 语言。后来 jeff greenberg 将其移植到 javascript 中,并经过 andrew b. king 修改并提出了一种更为高效的版本。
复制代码 代码如下:
//credit: Speed Up Up Your Site (New Riders, 2003)
var iterations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;
if (leftover > 0) {
do {
process(values[i++]);
} while (--leftover > 0);
}
do {
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
} while (--iterations > 0);
这种技术的工作原理是通过计算values的长度除以 8 以得到需要迭代的次数,并以math.floor()函数来保证结果为整数, 然后再计算不能被 8 整除时的餘数,并对这些元素单独进行处理,其餘则 8 次为单次展开次数来进行迭代。
我将这种装置再加以封装,可以得到一种带有异步味道的 api。
复制代码 代码如下:
function duff(array, mapper) {
var n = Math.floor(array.length / 8);
var l = array.length % 8;
var i = 0;
if (l > 0) {
do {
mapper(array[i++]);
} while (--i > 0);
}
do {
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
mapper(array[i++]);
} while (--n > 0);
}
duff([...], function(item) {
//...
});
这里是一组对於以上三种迭代解决方案的性能测试及其结果。
5.2 非原生循环
在任何编程语言中,能够实现循环的,不止语言所提供的原生循环语句,还可以通过其他方式来间接实现。
让我们先来温习一下高中数学的一点内容——数列的通项公式。
复制代码 代码如下:
bacause
a[1] = 1
a[n] = 2 * a[n - 1] + 1
so
a[n] + 1 = 2 * a[n - 1] + 2
= 2 * (a[n - 1] + 1)
(a[n] + 1) / (a[n - 1] + 1) = 2
then
a[n] + 1 = (a[n] + 1) / (a[n - 1] + 1) * (a[n - 1] + 1) / (a[n - 2] + 1) * ... * (a[2] + 1) / (a[1] + 1) * (a[i] + 1)
a[n] + 1 = 2 * 2 * ... * 2 * 2
a[n] + 1 = 2^n
a[n] = 2^n - 1
final
a[n] = 2^n - 1
看了上面这段简单的演算,估计你也猜到我们将要讨论的内容了吧。 是的,我们还可以使用递归来实现循环。
递归是数学和计算机科学中非常重要的一种应用方法,它是指函数在其使用时调用其自身。
在 node.js 社区中,递归被用来实现一种非常重要的技术:中间件技术。 这是一段尚未公佈的新版本的 webjs 中的中间件实现代码。
复制代码 代码如下:
/**
* Middlewares run method
* @param {String} url Current request url
* @param {Object} req the request object
* @param {Object} res the response object
* @param {Function} out Complete Callback
* @return {Function} the server
*/
server.runMiddlewares = function(url, req, res, out) {
var index = -1;
var middlewares = this._usingMiddlewares;
// run the next middleware if it is exists
function next(err) {
index++;
// current middleware
var curr = middlewares[index];
if (curr) {
var check = new RegExp(curr.route);