JS中的同步和異步

javascript語言是一門「單線程」的語言,不像java語言,類繼承Thread再來個thread.start就能夠開闢一個線程,因此,javascript就像一條流水線,僅僅是一條流水線而已,要麼加工,要麼包裝,不能同時進行多個任務和流程。javascript

因此同步和異步,不管如何,作事情的時候都是隻有一條流水線(單線程),同步和異步的差異就在於這條流水線上各個流程的執行順序不一樣java

  一、最基礎的異步是setTimeout和setInterval函數,很常見,可是不多人有人知道其實這就是異步,由於它們能夠控制js的執行順序。咱們也能夠簡單地理解爲:能夠改變程序正ajax

     常執行順序的操做就能夠當作是異步操做promise

 1 <script type="text/javascript">
 2         console.log( "1" );
 3         setTimeout(function() {
 4             console.log( "2" )
 5         }, 0 );
 6         setTimeout(function() {
 7             console.log( "3" )
 8         }, 0 );
 9         setTimeout(function() {
10             console.log( "4" )
11         }, 0 );
12         console.log( "5" );
13 </script>

              輸出順序:瀏覽器

             

    在執行程序的時候,瀏覽器會默認setTimeout以及ajax請求這一類的方法都是耗時程序(儘管可能不耗時),將其加入一個隊列中,該隊列是一個存儲耗時程序的隊列,網絡

    在全部不耗時程序執行事後,再來依次執行該隊列中的程序。異步

  二、又回到了最初的起點——javascript是單線程。單線程就意味着,全部任務須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就不async

     得不一直等着。因而就有一個概念——任務隊列。若是排隊是由於計算量大,CPU忙不過來,倒也算了,可是不少時候CPU是閒着的,由於IO設備(輸入輸出設備)很函數

     慢(好比Ajax操做從網絡讀取數據),不得不等着結果出來,再往下執行。因而JavaScript語言的設計者意識到,這時主線程徹底能夠無論IO設備,掛起處於等待中的任spa

     務,先運行排在後面的任務。等到IO設備返回告終果,再回過頭,把掛起的任務繼續執行下去。

     因而,全部任務能夠分紅兩種,一種是同步任務(synchronous),另外一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務

     執行完畢,才能執行後一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有等主線程任務執行完畢,"任務隊列"開始通知主線程,

     請求執行任務,該任務纔會進入主線程執行。

     

     具體來講,異步運行機制以下:
    (1)全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)。
    (2)主線程以外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果, 就在"任務隊列"之中放置一個事件。
    (3)一旦"執行棧"中的全部同步任務執行完畢,系統就會讀取"任務隊列",看看裏面有哪些事件。那些對應的異步任務,因而結束等待狀態,進入執行棧,開始執行。
    (4)主線程不斷重複上面的第三步。
     只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重複。
     "任務隊列"是一個事件的隊列(也能夠理解成消息的隊列),IO設備完成一項任務,就在"任務隊列"中添加一個事件,表示相關的異步任務能夠進入"執行棧"了。主線程
     讀取"任務隊列",就是讀取裏面有哪些事件。
     "任務隊列"中的事件,除了IO設備的事件之外,還包括一些用戶產生的事件(好比鼠標點擊、頁面滾動等等),好比$(selectot).click(function),這些都是相對耗時的操做。
     只要指定過這些事件的回調函數,這些事件發生時就會進入"任務隊列",等待主線程讀取。
     所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼,前面說的點擊事件$(selectot).click(function)中的function就是一個回調函數。 異步任務必須指定回調函
     數,當主線程開始執行異步任務,就是執行對應的回調函數。例如ajax的success,complete,error也都指定了各自的回調函數,這些函數就會加入「任務隊列」中,等待
     執行。
     三、Promise對象用於異步操做,它表示一個還沒有完成且預計在將來完成的異步操做。
       Promise的真正強大之處在於它的多重鏈式調用,能夠避免層層嵌套回調

      Promise對象表明一個未完成、但預計未來會完成的操做。
      它有如下三種狀態:

      • pending:初始值,不是fulfilled,也不是rejected
      • fulfilled:表明操做成功
      • rejected:表明操做失敗
/* 例3.1 */
//構建Promise
var promise = new Promise(function (resolve, reject) {
    if (/* 異步操做成功 */) {
        resolve(data);
    } else {
        /* 異步操做失敗 */
        reject(error);
    }
});

相似構建對象,咱們使用new來構建一個PromisePromise接受一個「函數」做爲參數,該函數的兩個參數分別是resolvereject。這兩個函數就是就是「回調函數」,由JavaScript引擎提供。

resolve函數的做用:在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去;
reject函數的做用:在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去。

Promise實例生成之後,能夠用then方法指定resolved狀態和reject狀態的回調函數。

/* 接例3.1 */
promise.then(onFulfilled, onRejected);

promise.then(function(data) {
  // do something when success
}, function(error) {
  // do something when failure
});

then方法會返回一個Promise。它有兩個參數,分別爲Promise從pending變爲fulfilledrejected時的回調函數(第二個參數非必選)。這兩個函數都接受Promise對象傳出的值做爲參數
簡單來講,then就是定義resolvereject函數的,其resolve參數至關於:

function resolveFun(data) {
    //data爲promise傳出的值
}

而新建Promise中的'resolve(data)',則至關於執行resolveFun函數。
Promise新建後就會當即執行。而then方法中指定的回調函數,將在當前腳本全部同步任務執行完纔會執行

相關文章
相關標籤/搜索