什么构成异步JavaScript?

时间:2013-05-17 20:49:57

标签: javascript asynchronous

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%理解异步性。看起来它不仅仅是查看函数并查明它是否使用回调。

1 个答案:

答案 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}执行处理也会更新进度条的原因}。