再談Javascript中的異步以及如何異步
為什么需要異步?why?來(lái)看一段代碼。
問(wèn)題1:
for(var i=0;i<100000;i++){ } alert('hello world!!!');
這段代碼的意思是執(zhí)行100...次后再執(zhí)行alert,這樣帶來(lái)的問(wèn)題是,嚴(yán)重堵塞了后面代碼的執(zhí)行,至于為什么,主要是因?yàn)镴S是單線程的。
問(wèn)題2:
我們通常要解決這樣一個(gè)問(wèn)題,如果我們需要在head里面加入script代碼的話,一般會(huì)將代碼寫在window.onload
里面(如果操作了dom的話),你有沒(méi)有想過(guò),為什么要加window.onload
?原因就是你在操作dom的時(shí)候script后面的html代碼瀏覽器還沒(méi)有開始加載,結(jié)果人家還沒(méi)有出生你就想著去娶她,這可能嗎?當(dāng)然不可能,加上window。onload
之所以可以是因?yàn)椋?code>window.onload里面的代碼是在文檔全部加載完畢后執(zhí)行的,也就相當(dāng)于異步。
問(wèn)題3:
有時(shí)候頁(yè)面并不需要一次性把所有的代碼都加載,更多的時(shí)候我們是按照某個(gè)需求才去加載某段代碼的。
什么是單線程?
你可以這樣理解單線程就是代碼一段一段的執(zhí)行,先執(zhí)行前面的,前面的執(zhí)行完了再執(zhí)行后面的。
那JS中有哪些是異步的呢?
我相信這個(gè)東西,幾乎都用爛了,它就是setTimeout/setInterval當(dāng)然還有Ajax,Ajax異步我相信大家都知道,當(dāng)然也可以同步但沒(méi)人那么去做,但是對(duì)于setTimeout和setInterval是異步可能有些小伙伴不同了解,下面說(shuō)說(shuō)為什么說(shuō)setTimeout是異步的。
setTimeout(function(){ console.log(0); },0) console.log(1); // 1 // 0
運(yùn)行這段代碼后先打印的是1,而不是0,有些小伙伴是不是開始迷惑了,這里我們雖然給setTimeout設(shè)置的是0秒后執(zhí)行console.log(0)
,但是這個(gè)setTimeout很特別,因?yàn)樗钱惒降?,我們先拋開這里為什么打印的是1然后才是0,先來(lái)聊聊什么是異步。
什么是異步?
比方說(shuō)有些飯店你去吃飯需要提前預(yù)定,等其他人吃完你才能去,因此在其他人吃飯的時(shí)候你可以去干其他的事情,等其他人吃完了會(huì)有人來(lái)通知你,于是你可以去了,那么對(duì)于代碼來(lái)說(shuō),如ajax,你定義了一個(gè)回調(diào)方法,這個(gè)回調(diào)方法并不會(huì)當(dāng)時(shí)就去執(zhí)行,而是等待服務(wù)器響應(yīng)完成之后才會(huì)去執(zhí)行這段代碼。
我們回到前面那段setTimeout身上,它的工作原理是這樣的,當(dāng)你定義setTimeout那一刻起(不管時(shí)間是不是0),js并不會(huì)直接去執(zhí)行這段代碼,而是把它扔到一個(gè)事件隊(duì)列里面,當(dāng)頁(yè)面中所有同步任務(wù)都干完了以后,才會(huì)去執(zhí)行事件隊(duì)列里面的代碼。什么是同步,除了異步代碼就是同步—_—。
JS怎么實(shí)現(xiàn)異步?
1.利用setTimout實(shí)現(xiàn)異步
setTimeout(function(){ console.log(document.getElementByTagName('body')[0]); },0)
但是setTimeout有些小小的問(wèn)題,就是時(shí)間不精確,如果你想更快的執(zhí)行這段代碼我們可以使用html5提供的一個(gè)函數(shù)?! ?/p>
requestAnimationFrame(function(){ console.log(document.getElementByTagName('body')[0]); })
requestAnimationFrame和setTimeout的區(qū)別就在于requestAnimationFrame比setTimeout更快執(zhí)行,因此很多人用requestAnimationFrame來(lái)制作動(dòng)畫。
2.動(dòng)態(tài)創(chuàng)建script標(biāo)簽
var head = document.getElementByTagName('head')[0]; var script = document.createElement('script'); script.src = '追夢(mèng)子.js'; head.appendChild('script');
3.利用script提供的defer/async
<script src="xx.js" defer></script>
defer:當(dāng)頁(yè)面加載完畢以后才去執(zhí)行這段代碼。
<script src="xx.js" async></script>
async:異步執(zhí)行script代碼
不過(guò)異步也是缺點(diǎn)的,比如下面這段代碼:
正常代碼:
try{ throw new Error('hello world'); }catch(err){ console.log(err); } // Error: hello world(…)
異步代碼:
try{ setTimout(function(){ throw new Error('hello world'); },0) }catch(err){ console.log(err); } // ReferenceError: setTimout is not defined(…)
可以發(fā)現(xiàn)catch里面的代碼并沒(méi)有執(zhí)行,也就是說(shuō)try無(wú)法捕獲異步里面的代碼。
總結(jié)
關(guān)于JS中的異步以及如何異步到這就基本結(jié)束,關(guān)于JS的異步算是老生常談了,但是還是希望本文的內(nèi)容對(duì)大家能有一些幫助。
相關(guān)文章
javascript使用正則獲取url上的某個(gè)參數(shù)
使用indexOf取得?之后的參數(shù),以&使split進(jìn)行分割成數(shù)組,下面展示了一個(gè)從url上獲取名為MenuCode參數(shù)的過(guò)程2014-09-09在多個(gè)頁(yè)面使用同一個(gè)HTML片段《續(xù)》
上一篇文章中我們使用textarea來(lái)模擬AJAX的返回結(jié)果,造成了一些誤解。 這里我們首先用asp.net的Generic Handler做一個(gè)簡(jiǎn)單的后臺(tái)來(lái)重現(xiàn)這個(gè)AJAX過(guò)程。2011-03-03基于JavaScript實(shí)現(xiàn)手機(jī)短信按鈕倒計(jì)時(shí)(超簡(jiǎn)單)
在淘寶等購(gòu)物網(wǎng)站,我們都會(huì)看到一個(gè)發(fā)送短信倒計(jì)時(shí)的按鈕,究竟是如何實(shí)現(xiàn)的呢?下面小編通過(guò)本篇文章給大家分享一段代碼關(guān)于js實(shí)現(xiàn)手機(jī)短信按鈕倒計(jì)時(shí),需要的朋友參考下2015-12-12Express與NodeJs創(chuàng)建服務(wù)器的兩種方法
本文主要介紹了NodeJs創(chuàng)建Web服務(wù)器;Express創(chuàng)建Web服務(wù)器的兩種方法,具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02