1. 程式人生 > >JavaScript的非同步處理

JavaScript的非同步處理

Javascript語言的執行環境是"單執行緒"(single thread,就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務,以此類推)。

為了解決這個問題,Javascript語言將任務的執行模式分成兩種:同步(Synchronous)和非同步(Asynchronous)。

“同步模式" 就是上一段的模式,後一個任務等待前一個任務結束,然後再執行,程式的執行順序與任務的排列順序是一致的、同步的;"非同步模式"則完全不同,每一個任務有一個或多個回撥函式(callback),前一個任務結束後,不是執行後一個任務,而是執行回撥函式,後一個任務則是不等前一個任務結束就執行,所以程式的執行順序與任務的排列順序是不一致的、非同步的。

“非同步模式" 非常重要。在瀏覽器端,耗時很長的操作都應該非同步執行,避免瀏覽器失去響應,最好的例子就是Ajax操作。在伺服器端,"非同步模式"甚至是唯一的模式,因為執行環境是單執行緒的,如果允許同步執行所有http請求,伺服器效能會急劇下降,很快就會失去響應。

回撥

回撥是 JS 中最原始,也是最古老的非同步通知機制。

function asyncFn(callback) {
  // 利用setTimeout模擬非同步
  setTimeout(function () {
    console.log('執行完畢');
    callback(); // 發通知
  }, 2000);
}

asyncFn(function () {
  console.log('我會在2s後輸出');
});

事件監聽

任務的執行不取決程式碼的順序,而取決於某一個事件是否發生。

監聽函式有:on,bind,listen,addEventListener,observe

還是以f1和f2為例。首先,為f1繫結一個事件(採用jquery寫法)。
f1.on('done',f2);
上面程式碼意思是,當f1發生done事件,就執行f2。

釋出訂閱

promise

(1)promise物件是commonJS工作組提出的一種規範,一種模式,目的是為了非同步程式設計提供統一介面。

(2)promise是一種模式,promise可以幫忙管理非同步方式返回的程式碼。他講程式碼進行封裝並新增一個類似於事件處理的管理層。我們可以使用promise來註冊程式碼,這些程式碼會在在promise成功或者失敗後執行。

(3)promise完成之後,對應的程式碼也會執行。我們可以註冊任意數量的函式再成功或者失敗後執行,也可以在任何時候註冊事件處理程式。

(4)promise有兩種狀態:1、等待(pending);2、完成(settled)。

promise會一直處於等待狀態,直到它所包裝的非同步呼叫返回/超時/結束。

(5)這時候promise狀態變成完成。完成狀態分成兩類:1、解決(resolved);2、拒絕(rejected)。

(6)promise解決(resolved):意味著順利結束。promise拒絕(rejected)意味著沒有順利結束。

//promise
var p=new Promise(function(resolved))
//在這裡進行處理。也許可以使用ajax
setTimeout(function(){
   var result=10*5;
   if(result===50){
      resolve(50);
   }else{
     reject(new Error('Bad Math'));
  }
},1000);
});
p.then(function(result){
    console.log('Resolve with a values of %d',result);
});
p.catch(function(){
   console.error('Something went wrong');
});

(1)程式碼的 關鍵在於setTimeout()的呼叫。

(2)重要的是,他呼叫了函式resolve()和reject()。resolve()函式告訴promise使用者promise已解決;reject()函式告訴promise使用者promise未能順利完成。

(3)另外還有一些使用了promise程式碼。注意then和catch用法,可以將他們想象成onsucess和onfailure事件的處理程式。

(4)巧妙地方是,我們將promise處理與狀態分離。也就是說,我們可以呼叫p.then(或者p.catch)多少次都可以,不管promise是什麼狀態。

(5)promise是ECMAscript 6管理非同步程式碼的標準方式,javascript庫使用promise管理ajax,動畫,和其他典型的非同步互動。

簡單的說,它的思想是:每一個非同步任務返回一個promise物件,該物件有一個then方法,允許指定回撥函式。

f1.then(f2);

Promise.all

 //使用場景,同時從不同地方請求多條資料時
    Promise.all([
        $.ajax({
            url:"1.txt"
        }),
        $.ajax({
            url:"2.txt"
        })
    ]).then(
        (data)=>{
            console.log(data)
        }
    )

generator

生成器函式 可以暫停

 //1.生成器函式  優點 先等待非同步完成 再執行下面的程式碼
        //yield 後面的值給了下一個next() 
    function *show(){
        alert(1);
       let data= yield new Promise((resolve,reject)=>{
            setTimeout(() => {
                resolve(100);
            }, 5000);
        })
        console.log(data);
        alert(2);
    }
        //2.呼叫next() 完整
        //3.變數去接 生成器函式
    //生成器函式呼叫必須配合 .next
    let s=show();
    let p=s.next();
    console.log(p);
    console.log(p.value);
    let m= p.value.then((data)=>{
        s.next(data)
        console.log(data);
    })
    
   
    // p.value.then((data)=>{
    //     s.next(data);
    // })

    //引數  變數.next(引數) =>let 變數 =>yield
    //返回 yield()===> 變數.next() 

async/await

當前 JavaScript 中,處理非同步的最佳方案。

async函式返回一個 Promise 物件,可以使用then方法添加回調函式。當函式執行的時候,一旦遇到await就會先返回,等到非同步操作完成,再接著執行函式體內後面的語句。
async函式內部return語句返回的值,會成為then方法回撥函式的引數。

 async function show() {
        alert(1);
        let data = await new Promise((resolve,reject)=>{
            //網路請求時間來決定的
            setTimeout(() => {
                resolve(100)
            }, 3000);
        })
        console.log(data)
        let Data = await new Promise((resolve,reject)=>{
            //網路請求時間來決定的
            setTimeout(() => {
                resolve({
                    name:"heson",
                    age:12
                })
            }, 3000);
        })
        console.log(Data)
        alert(2);
    }
    show();