之前的笔记没保存没掉了,好气,重新写!
填坑……
现在与将来
在单个JS文件中,程序由许多块组成,这些块有的现在执行,有的将来执行,最常见的块单位是函数。
程序中'将来'执行的部分并不一定在'现在'运行的部分执行完之后就立即执行,即异步执行将来的部分。
//异步请求data数据
_.ajax('data');
//打印data数据
//一般情况下是打印不出来的
console.log(data);
一般的ajax请求都不是同步完成,如果要正确打印出data,最简单的方法是使用一个回调函数。
//异步请求data数据
_.ajax('url', function(data) {
//取到数据并打印了出来
console.log(data);
});
异步控制台
console对象并不是ECMA标准中的规定的,而是宿主环境(浏览器)添加到Javascript中的。
因此,不同的浏览器和Javascript环境可以按照自己的意愿来实现,有时候这个会引起混淆。
明确一点讲,有些情况下,某些浏览器的console.log(..)并不会把传入的内容立即输出。出现这种情况的主要原因是,在许多程序(not only Javascipt)中,I/O是非常低速的阻塞部分。所以,浏览器在后台异步处理控制器I/O能够提高性能,这时用户(开发也是)可能根本意识不到其发生。
比如说:
var obj = {
index: 1
};
console.log(obj);
obj.index++;
严格来讲,obj.index++应该在打印之后才执行。但是,这段代码运行的时候,浏览器可能会认为需要把控制台I/O延迟到后台,这种情况下,++可能已经执行,因此会打印出index:2。
异步特殊情况
并发
当两个异步请求都完成,才调用某个函数:
var a, b;
//只有当两个异步请求都完成时才会调用指定函数
_.ajax('url1', function() {
a = 1;
if (a && b) {
log();
}
});
_.ajax('url2', function() {
b = 1;
if (a && b) {
log();
}
});
function log() {
console.log(a + b);
}
竞态
第二种情况是只要有一个异步请求完成,就调用某个函数。
var a;
//有一个异步完成就会调用函数
//第二个会被舍弃
_.ajax('url1', function(data) {
a = data;
if (!a) {
log();
}
});
_.ajax('url2', function(data) {
a = data;
if (!a) {
log();
}
});
function log() {
console.log(a);
}
节流阀
第三种情况是当请求到大量数据并需要进行处理时,可以通过异步来分批处理。
var res = [];
//节流阀函数
function fn(data) {
//每次处理1000个数据
//书上未做这个判断 最后可能只有少量数据
var chunk = data.length > 1000 ? data.splice(0, 1000) : data.splice(0, data.length);
//处理数据 这里只是一个简单案例
res = res.concat(chunk.map(function(val) {
return val * 2;
}));
//是否仍有数据
if (data.length > 0) {
//异步处理
setTimeout(function() {
fn(data);
}, 0);
}
}
//ajax获取大量数据
_.ajax('url', data);
由于setTimeout是task事件(详细介绍可以看我的另外一个博客),所以会在主线程其他函数完事后插进去,保证页面流畅。