之前的笔记没保存没掉了,好气,重新写!
填坑……
现在与将来
在单个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事件(详细介绍可以看我的另外一个博客),所以会在主线程其他函数完事后插进去,保证页面流畅。