参考http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
异步和同步编程思想:做一份卷子的时候,遇到一道难题,同步会仔细想直到解决了才去做下一题,异步是直接跳过这题,然后把其他的都做完了,再做这个难题
同步:上一件事情只有完成才开始下一件事情(js大部分都是同步编程的)
异步:规划做一件事情 但是不是当前立马执行这件事 需要等一定时间,这样的话 我们不会等着它执行 而是执行下面的代码 "只有当下面的代码执行完了 才会返回执行处理之前的事情 如果下面的没执行完 那么不管之前的事情有没有到时间 都必须等着"
在js中异步编程有四种情况:定时器,所有的事件绑定 ,ajax读取数据的时候 ,回调函数
window.setTimeout(function() { console.log(5) }, 100) window.setTimeout(function() { console.log(3) }, 10) window.setTimeout(function() { console.log(4) }, 10) window.setTimeout(function() { console.log(2) }, 0) console.log(1)
会依次打印1,2,3,4,5
浏览器看到定时器,会记录当前定时器多久以后执行,即使定时器定时0,浏览器会将其变成自己最小的定时时间,然后排队,时间越短的越排在前面,同样时间的按出现的先后,排队完后,再执行(无视作用域)其他代码,最后执行排好的队列
为了防止出错,自己写这些异步的时候,写个注释,还有不影响整体代码的情况下,尽可能靠后写
有个经典案例,有5个li,每个里面的文本是当前索引,点击li,显示相应的索引
然后就这样写:
var lis = document.getElementsByTagName("li"); for (var i = 0; i < lis.length; i++) { var cur = lis[i]; lis[i].onclick = function () { console.log(i) } }
结果发现点击什么都是打印5,分析下,浏览器执行的时候,遇到for,首先i=0,然后绑定点击事件,请注意,当绑定事件的时候,只是绑定一个函数,里面是什么根本没管,然后循环完之后,i=5,此时,每个li上都有绑定事件,当点击某一个li的时候,执行函数,打印i,而i已经变成了5.
正确的做法是保留i,比如
var lis = document.getElementsByTagName("li"); for (var i = 0; i < lis.length; i++) { var cur = lis[i]; cur["index"] = i; lis[i].onclick = function () { console.log(this["index"]) } }
然后看这个demo
function a() { window.setTimeout(function() { console.log(5) }, 100) window.setTimeout(function() { console.log(3) }, 0) console.log(1) } function b() { window.setTimeout(function() { console.log(6) }, 100) window.setTimeout(function() { console.log(4) }, 0) console.log(2) } a() b()
依然会依次输出1,2,3,4,5,6,也就是说跨作用域,浏览器的队列和作用域无关,只要是定时器都会在普通代码之后执行.