在 MDN 的 JavaScript 系列中咱們已經學習了 callback、promise、generator、async/await。而在這一篇文章中,做者將以實際樣例闡述異步發展歷史,介紹每種實現方式的優點與不足,以期幫助讀者熟悉歷史進程並把握異步發展的脈絡。 javascript
幾十年前的導航網站,清爽又簡單,沒有什麼特別的功能,只是單純的展現,現成的網頁在服務器上靜靜躺着,高效毫無壓力,讓人很喜歡。html
幾十年後的今天,靜態頁面遠不能知足用戶的需求,網站變得複雜起來,用戶交互愈來愈頻繁,從而產生大量複雜的內部交互,爲了解決這種複雜,出現了各類系統「模式」,從而很容易的在外部獲取數據,並實時展現給用戶。java
獲取外部數據實際上就是「網絡調用」,這個時候「異步」這個詞彙出現了。編程
異步指兩個或兩個以上的對象或事件不一樣時存在或發生(或多個相關事物的發生無需等待其前一事物的完成)
異步 callbacks其實就是函數,只不過是做爲參數傳遞給那些在後臺執行的其餘函數。當那些後臺運行的代碼結束,就調用 callbacks 函數,通知你工做已經完成,或者其餘有趣的事情發生了。
場景segmentfault
let readFile = (path, callBack) => { setTimeout(function () { callBack(path) }, 1000) } readFile('first', function () { console.log('first readFile success') readFile('second', function () { console.log('second readFile success') readFile('third', function () { console.log('third readFile success') readFile('fourth', function () { console.log('fourth readFile success') readFile('fifth', function () { console.log('fifth readFile success') }) }) }) }) })
優勢:promise
缺點:服務器
一個 Promise對象表明一個在這個 promise 被建立出來時不必定已知的值。它讓您可以把異步操做最終的成功返回值或者失敗緣由和相應的處理程序關聯起來。 這樣使得異步方法能夠像同步方法那樣返回值:異步方法並不會當即返回最終的值,而是會返回一個 promise,以便在將來某個時候把值交給使用者。
場景網絡
let readFile = (path) => { return new Promise((resolve, reject) => { setTimeout(() => { if (!path) { reject('error!!!') } else { console.log(path + ' readFile success') resolve() } }, 1000) }) } readFile('first') .then(() => readFile('second')) .then(() => readFile('third')) .then(() => readFile('fourth')) .then(() => readFile('fifth'))
優勢:異步
缺點:async
Generator函數是 ES6 中提供的一種 異步編程解決方案。語法上,首先能夠把它理解成, Generator函數是一個 狀態機,封裝了多個內部狀態,須要使用 next()函數來繼續執行下面的代碼。
特徵
場景
var readFile = function (name, ms) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name + '讀完了') resolve() }, ms) }) } var gen = function* () { console.log('指定generator') yield readFile('first', 1000) yield readFile('second', 2000) yield readFile('third', 3000) yield readFile('forth', 4000) yield readFile('fifth', 5000) return '完成了' } var g = gen() var result = g.next() result.value .then(() => { g.next() }) .then(() => { g.next() }) .then(() => { g.next() }) .then(() => { g.next() })
優勢:
缺點:
async functions 和 await 關鍵字是最近添加到 JavaScript 語言裏面的。它們是 ECMAScript 2017 JavaScript 版的一部分(參見 ECMAScript Next support in Mozilla)。簡單來講,它們是基於 promises 的語法糖,使異步代碼更易於編寫和閱讀。經過使用它們,異步代碼看起來更像是老式同步代碼,所以它們很是值得學習。
場景 1
var readFile = function (name, ms) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(name + '讀完了') resolve() }, ms) }) } async function useAsyncAwait() { await readFile('first', 1000) await readFile('second', 2000) await readFile('third', 3000) await readFile('forth', 4000) await readFile('fifth', 5000) console.log('async文件閱讀完畢') } useAsyncAwait()
優勢
語義更清晰、簡潔
缺點
場景 2 場景 1 中的代碼,其實 second,third 的僞請求其實並不依賴於 first,second 的結果,但它們必須等待前一個的完成才能繼續,而咱們想要的是它們同時進行,因此正確的操做應該是這樣的。
async function useAsyncAwait() { const first = readFile('first', 1000) const second = readFile('second', 2000) const third = readFile('third', 3000) const forth = readFile('forth', 4000) const fifth = readFile('fifth', 5000) console.log('async文件閱讀完畢') await first await second await third await forth await fifth } useAsyncAwait()
在這裏,咱們將三個 promise 對象存儲在變量中,這樣能夠同時啓動它們關聯的進程。
在這篇文章中,咱們已經介紹了 JavaScript 異步發展史中 --- callback、promise、generator、async/await 的使用方式、優勢與缺點。
發展史 | 優勢 | 缺點 |
---|---|---|
callback | 解決了同步問題 | 回調地獄、可讀性差、沒法 try / catch 、沒法 return |
promise | 必定程度上解決了回調地獄的可讀性 | 沒法取消、任務多時,一樣存在語義不清晰 |
generator | 能夠控制函數的執行,能夠配合 co 函數庫使用 | 流程管理卻不方便(即什麼時候執行第一階段、什麼時候執行第二階段 |
async/await | 語義更清晰、簡潔,內置執行器 | 認知不清晰可能會形成大量 await 阻塞(程序並不會等在原地,而是繼續事件循環,等到響應後繼續往下走)狀況 |
而在現有的異步解決方案中,async/await 是使用人數最多的,它帶給咱們最大的好處即同步代碼的風格,語義簡潔、清晰。