demo準備的啰嗦了,如果你同我一樣是個急性子,可以直接忽略
捂臉
需求
demo中src文件里有a、b、c三個json文件,需求是我們需要依次請求它們,并且打印它們的值。
發展史
- ES5 - 金字塔
- ES6 - 鏈式
- ES6 - 暫停
- ES7 - 同步
ES5 - 金字塔
首先我們來到ES5的時代,為完成以上的需求寫下如下的代碼:
$.ajax('./src/a.json').done((a)=>{
console.log(a.data) // 打印a文件
$.ajax('./src/a.json').done((b)=>{
console.log(b.data) // 打印b文件
$.ajax('./src/a.json').done((c)=>{
console.log(c.data) // 打印c文件
})
})
})
嗯,也不錯啊,一層套著一層,也算清晰明了了。如果當我們的需要改成100個文件的依次獲取呢?此時,如果還這樣寫的話,那歡迎你來到回調地獄
。
如果我們嵌套很多的代碼,像金字塔一樣的堆疊起來,不僅僅讓代碼顯得更加難看、臃腫,也讓項目變得越來越不好維護。
ES6 - 鏈式
我們來到了ES6的時代,這個時代的有個產物叫做promise。
通過promise我們可以將代碼鏈式的調用?改成??如下的代碼
function request(url){
return new Promise((resolve, reject)=>{
$.ajax(url).done((data)=>{
resolve(data)
}).fail((err)=>{
reject(err)
})
})
}
request('./src/a.json').then((a)=>{
console.log(a)
return request('./src/b.json')
}).then((b)=>{
console.log(b)
return request('./src/c.json')
}).thne((c)=>{
console.log(c)
})
相比金字塔
式嵌套的代碼,此時的代碼更加的簡潔,也更容易維護,但是也只不過是將嵌套改成了上下鏈接調用。
ES6 - 暫停
Generator 函數是 ES6 提供的一種異步編程解決方案,可以理解成內部有很多狀態的狀態機。
generator函數與普通函數區別:
- 定義的時候多了個
*
號 - 函數內部使用
yield
來定義不同的狀態 - 調用的時候,需要將函數賦值給某個變量,每個變量之間的狀態互不影響
- 使用
next()
函數調用下一個狀態
function request(url){
$.ajax(url).done((data)=>{
generator.next(data)
})
}
function* generatorFn(){
let a = yield request('./src/a.json')
console.log(a)
let b = yield request('./src/b.json')
console.log(b)
let c = yield request('./src/c.json')
console.log(c)
}
var generator = generatorFn()
generator.next()
以上代碼定義了generatorFn函數并賦值給generator,在定義request函數的時候,當請求到數據的時候,調用generator的next方法。
ES7 async/await
萬眾矚目,神器登場 async/await 。
先上代碼:
(async () => {
let a = await $.ajax('./src/a.json')
console.log(a)
let b = await $.ajax('./src/b.json')
console.log(b)
let c = await $.ajax('./src/c.json')
console.log(c)
})
async函數是generator函數的語法糖,只是將*
變成了async,yield
改成了await
,但是代碼卻精簡了這么多,它們直接的區別有以下幾點:
- async函數不用手動去調用next() 函數
- async函數返回值是promise,generator函數返回的是Iterator
async函數可以看成一個包含多個異步操作的promise的對象,await就是then的語法糖。
四種方式中最精簡的方式。使用async處理回調函數,代碼會異常的清新,我們寫起來也會很爽很舒服。
為什么會有這種感覺呢?
因為它是最符合我們寫代碼的習慣,用同步的寫法去解決異步的代碼。
參考文檔: