1. 程式人生 > >JS中的非同步,以及如何非同步

JS中的非同步,以及如何非同步

為什麼需要非同步?why?來看一段程式碼。

問題1:

for(var i=0;i<100000;i++){

}

alert('hello world!!!');

  這段程式碼的意思是執行100...次後再執行alert,這樣帶來的問題是,嚴重堵塞了後面程式碼的執行,至於為什麼,主要是因為JS是單執行緒的。

問題2:

  我們通常要解決這樣一個問題,如果我們需要在head裡面加入script程式碼的話,一般會將程式碼寫在window.onload裡面(如果操作了dom的話),你有沒有想過,為什麼要加window.onload?原因就是你在操作dom的時候script後面的html程式碼瀏覽器還沒有開始載入,結果人家還沒有出生你就想著去娶她,這可能嗎?當然不可能,加上window。onload之所以可以是因為,window.onload裡面的程式碼是在文件全部載入完畢後執行的,也就相當於非同步。

問題3:

  有時候頁面並不需要一次性把所有的程式碼都載入,更多的時候我們是按照某個需求才去載入某段程式碼的。

什麼是單執行緒?

  你可以這樣理解單執行緒就是程式碼一段一段的執行,先執行前面的,前面的執行完了再執行後面的。

那JS中有哪些是非同步的呢?

  我相信這個東西,幾乎都用爛了,它就是setTimeout/setInterval當然還有Ajax,Ajax非同步我相信大家都知道,當然也可以同步但沒人那麼去做,但是對於setTimeout和setInterval是非同步可能有些小夥伴不同瞭解,下面說說為什麼說setTimeout是非同步的。

setTimeout(function(){
  console.log(0);
},0)

console.log(1);

// 1

// 0

執行這段程式碼後先列印的是1,而不是0,有些小夥伴是不是開始迷惑了,這裡我們雖然給setTimeout設定的是0秒後執行console.log(0),但是這個setTimeout很特別,因為它是非同步的,我們先拋開這裡為什麼列印的是1然後才是0,先來聊聊什麼是非同步。

什麼是非同步?

  比方說有些飯店你去吃飯需要提前預定,等其他人吃完你才能去,因此在其他人吃飯的時候你可以去幹其他的事情,等其他人吃完了會有人來通知你,於是你可以去了,那麼對於程式碼來說,如ajax,你定義了一個回撥方法,這個回撥方法並不會當時就去執行,而是等待伺服器響應完成之後才會去執行這段程式碼。

我們回到前面那段setTimeout身上,它的工作原理是這樣的,當你定義setTimeout那一刻起(不管時間是不是0),js並不會直接去執行這段程式碼,而是把它扔到一個事件佇列裡面,當頁面中所有同步任務都幹完了以後,才會去執行事件佇列裡面的程式碼。什麼是同步,除了非同步程式碼就是同步—_—。

JS怎麼實現非同步?

  1.利用setTimout實現非同步

setTimeout(function(){
  console.log(document.getElementByTagName('body')[0]);
},0)

  但是setTimeout有些小小的問題,就是時間不精確,如果你想更快的執行這段程式碼我們可以使用html5提供的一個函式。

requestAnimationFrame(function(){
  console.log(document.getElementByTagName('body')[0]);
})

  requestAnimationFrame和setTimeout的區別就在於requestAnimationFrame比setTimeout更快執行,因此很多人用requestAnimationFrame來製作動畫。

  2.動態建立script標籤

var head = document.getElementByTagName('head')[0];
var script = document.createElement('script');
script.src = '追夢子.js';
head.appendChild('script');

   3.利用script提供的defer/async

     <script src="xx.js" defer></script>

  defer:當頁面載入完畢以後才去執行這段程式碼。

  <script src="xx.js" async></script>

  async:非同步執行script程式碼

不過非同步也是缺點的,比如下面這段程式碼:

  正常程式碼:

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(…)

  可以發現catch裡面的程式碼並沒有執行,也就是說try無法捕獲非同步裡面的程式碼。