JavaScript的一个突出特点(或损害,取决于您对该主题的看法)是它的异步性质。我理解代码流是如何工作的,但我不是100%关于异步代码“异步”的原因。
当然,联系服务器或读/写数据库是一种异步操作。但通常非异步处理的事情呢?我可以编写使用回调的代码,使其整天都异步。
var arrayToIterate = [1,2,3,4,5,6,7,8,9, ... ]
//Say this array length is in the hundreds of millions.
var addArrayContents = function(array) {
var total = 0;
for (var i = 0, len = array.length; i <= len; i++) {
total = total + array[i];
}
return total;
};
var arrayTotal = addArrayContents(arrayToIterate);
var arrayToIterate = [1,2,3,4,5,6,7,8,9, ... ]
//Say this array length is in the hundreds of millions.
var addArrayContents = function(array, callback) {
var iterator = function(total, arIndex, cb) {
if (arIndex == array.length) {
return cb(total);
}
total = total + array[arIndex];
arIndex++;
iterator(total, arIndex, cb)
};
iterator(0, 0, callback);
};
addArrayContents(arrayToIterate, function(result){
console.log(result);
// Do stuff
});
正如你所知,两个函数都做同样的事情,一个是异步的,一个不是。是否有一个经验法则决定同步异步做某事的最佳时间?在上面的示例中,同步函数在将这些数字添加到一起时会陷入困境,而异步版本在运行时不会挂起。
我只是觉得我不能100%理解异步性。看起来它不仅仅是查看函数并查明它是否使用回调。
答案 0 :(得分:2)
第二个版本不是异步的......嵌套函数只是递归地调用它自己(对于一个大数组来说这是一个坏主意)。
要使其异步,您应该例如安排一个计时器(使用setTimeout
),以便稍后继续计算。
var index = 0;
var total = 0;
function step() {
if (index < array.length) {
total += array[index++];
setTimeout(step, 0);
} else {
callback(total);
}
}
setTimeout(step, 0);
在这种情况下,函数会立即返回调用者,并且计算完成后稍后(异步)将调用完成回调。
在内部实现例如setTimeout
的一种方法是保持一堆等待触发的计时器事件。当JS环境完成当前事件时,它将检查接下来要生成的内容,然后从调用处理程序的堆中删除该项。
另请注意,除了计时器事件外,还有鼠标事件,网络事件,消息事件等...通常计时器事件的优先级最低,因此只有在没有其他任何事情可以执行时才会调用代码(也是为什么时间不准确,指定的延迟只是最小延迟。)
即使没有其他事件,通常浏览器中的JS例如会在调用计时器处理程序之前首先进行DOM重新绘制(这就是为什么例如即使使用{{1}执行处理也会更新进度条的原因}。