js非同步程式設計發展

祝學友發表於2019-02-15

在最開始的時候,js非同步程式設計是一件很痛苦的事,不過隨著技術發展,現在寫非同步已經可以像寫同步一樣舒服了。

主要的變化過程:

回撥函式 ===>>> promise ===>>> generater ===>>> async/await

回撥函式時代

dosomething(sucessCallback, errCallback)
複製程式碼

這種寫法在多重非同步處理的時候很容易出現回撥地獄

promise寫法

promise最大的好處就是實現了鏈式呼叫的寫法,而且可以用catch來捕獲異常。
不過Promise 物件的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲為止;而且promise會吞掉錯誤,不向外部丟擲

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log(`Contents: ` + json);
}).catch(err => console.log(err));
複製程式碼

generator寫法

Generator 函式是協程在 ES6 的實現,最大特點就是可以交出函式的執行權,注意它不是語法糖。

  • 第一步,協程A開始執行。
  • 第二步,協程A執行到一半,進入暫停,執行權轉移到協程B。
  • 第三步,(一段時間後)協程B交還執行權。
  • 第四步,協程A恢復執行。
function* gen(x) {
  var y = yield x + 2;
  return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
g.throw(`出錯了`);
複製程式碼

yield之後的跟隨的物件或基本型別的值會被自動轉化為promise。
generator最麻煩的就是需要自己執行next去執行下一步

async/await 寫法

這是generator+co庫的一個es7語法糖,最接近同步的語法。
由於generator需要不斷地執行,於是有人寫了一個叫co的自執行函式庫。

var co = require(`co`);
co(gen);
複製程式碼

這樣generator就可以自動地執行了。於是就出現了async/await的寫法:

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName(`goog`).then(function (result) {
  console.log(result);
});
複製程式碼

async後面的函式返回的是一個promise物件,可以用.then的語法。

try {
    getStockPriceByName()
} catch(err) {
    console.log(error)
} finally {
    dosomething()
}
複製程式碼

錯誤處理方面也更加接近同步的語法。

總結

只要能夠寫es6語法,我們就可以用上async/await的語法來解決非同步程式設計的需要了,這是將會是相當方便的一個體驗,也會給後續的人一個更清晰的程式碼邏輯。

相關文章