受
javascript
語(yǔ)言特性的影響,編程過(guò)程中充斥著大量異步回調(diào)词疼,這會(huì)讓代碼維護(hù)起來(lái)特別麻煩俯树,一步步走向回調(diào)地獄。社區(qū)中最早提出Promise
解決方案贰盗,es6
將其融入語(yǔ)法標(biāo)準(zhǔn)许饿,并提供了generator
、async
舵盈,向類同步編程不斷努力陋率。本文會(huì)通過(guò)這三個(gè)方面演示類同步進(jìn)化過(guò)程。
1.Promise
Promise
提供異步編程的容器秽晚,包含異步代碼瓦糟,在得到異步結(jié)果時(shí),通過(guò)resolve
傳遞數(shù)據(jù)(resove
對(duì)應(yīng)then
所指定的函數(shù)赴蝇,其實(shí)也就是單個(gè)過(guò)程的異步回調(diào)菩浙,可以理解成將之前的回調(diào)函數(shù)放在then
方法中定義)。
以ajax請(qǐng)求封裝為例:
- 傳統(tǒng)形式
function ajax(url, success) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.status == 200 && xhr.readyState == 4) {
//將請(qǐng)求結(jié)果作為實(shí)參傳入成功回調(diào)
success(xhr.responseText);
}
}
}
//如果兩個(gè)異步過(guò)程有先后順序扯再,則會(huì)出現(xiàn)這種嵌套情況
ajax("http://vebcoder.cn:9527/api/getTypeOne", function (res) {
console.log(res);
ajax("http://vebcoder.cn:9527/api/goodList", function (res) {
console.log(res);
})
})
- Promise形式
function ajax(url) {
//promise容器包裹異步過(guò)程
return new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.status == 200 && xhr.readyState == 4) {
//將異步結(jié)果使用resolve進(jìn)行傳遞
resolve(xhr.responseText);
}
}
})
}
ajax("http://vebcoder.cn:9527/api/getTypeOne")
.then(res=>{
console.log(JSON.parse(res))
})
.then(()=>{
return ajax("http://vebcoder.cn:9527/api/goodList")
})
.then(res=>{
console.log(JSON.parse(res))
})
解決了回調(diào)函數(shù)橫向發(fā)展的問(wèn)題芍耘,變成了縱向發(fā)展結(jié)構(gòu)。直觀確實(shí)很直觀但是一大堆的then
方法熄阻,斋竞!接下來(lái)generator
登場(chǎng)
2.generator
乍一看,generator
不過(guò)是一個(gè)有多個(gè)返回值的函數(shù)而已秃殉,奧妙在于如果不調(diào)用next
方法坝初,代碼會(huì)停止執(zhí)行的。
- 基礎(chǔ)用法
//function后加*
function* Gen(){
console.log(1);
yield;
console.log(2)
yield;
console.log(3);
return;
}
//調(diào)用函數(shù)獲得指針對(duì)象
var g=Gen();
g.next();//1
g.next();//2
g.next();//3
第一次調(diào)用next
執(zhí)行到第一個(gè)yield
钾军,第三次執(zhí)行到函數(shù)末尾return
的位置鳄袍。
- 奧妙之處
function* Gen(){
//用變量接收yield命令
var res=yield;
console.log(res)
}
var g=Gen();
g.next();
//next傳入?yún)?shù)
g.next(100);//100
第一次調(diào)用next
方法,代碼執(zhí)行到yield
停止執(zhí)行吏恭。第二次調(diào)用next
傳入?yún)?shù)拗小,代碼繼續(xù)執(zhí)行,并將傳入next
的參數(shù)賦值給res
變量樱哼。next
方法可以帶一個(gè)參數(shù)哀九,該參數(shù)就會(huì)被當(dāng)作上一個(gè)yield
表達(dá)式的返回值。
那么我們就可以這樣做:
//上述封裝的ajax方法-傳統(tǒng)形式
function* Gen(){
//請(qǐng)求成功開始下一步
ajax("http://vebcoder.cn:9527/api/getTypeOne",res=>{g.next(res)})
// 接收yield返回值
let res=yield;
console.log(res)//請(qǐng)求的數(shù)據(jù)結(jié)果
}
var g=Gen();
// 開始執(zhí)行代碼
g.next();
//上述封裝的ajax方法-Promise形式
function* Gen(){
//請(qǐng)求成功開始下一步
ajax("http://vebcoder.cn:9527/api/getTypeOne").then(res=>{g.next(res)})
// 接收yield返回值
let res=yield;
console.log(res)//請(qǐng)求的數(shù)據(jù)結(jié)果
}
var g=Gen();
// 開始執(zhí)行代碼
g.next();
使用口訣:上一步回調(diào)搅幅,下一步阅束,接收yield
等待結(jié)果傳入
按理說(shuō)這種形式已經(jīng)不錯(cuò)了,不用再往下看了茄唐,除非你能忍紫⒙恪!
3.async
async
是generator
的語(yǔ)法糖,你只需關(guān)注兩部呼盆、步操作就行年扩。相當(dāng)于對(duì)Promise
和generator
進(jìn)行了融合。
async function Asy(){
//等待promise實(shí)例
let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne")
console.log(res)//請(qǐng)求的數(shù)據(jù)結(jié)果
}
Asy();
//結(jié)合自執(zhí)行函數(shù)
;(async function(){
let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne")
console.log(res)//請(qǐng)求的數(shù)據(jù)結(jié)果
}())
async
函數(shù)就是將Generator
函數(shù)的星號(hào)(*
)替換成async
宿亡,將yield
替換成await
常遂。
注意:await后面需要跟一個(gè)promise實(shí)例,無(wú)需手動(dòng)傳遞結(jié)果挽荠!
最后來(lái)一個(gè)對(duì)比(有次序的異步過(guò)程):
//傳統(tǒng)方式(對(duì)應(yīng)上述傳統(tǒng)ajax封裝形式)
ajax("http://vebcoder.cn:9527/api/getTypeOne", function (res) {
console.log(res);
ajax("http://vebcoder.cn:9527/api/goodList", function (res) {
console.log(res);
})
})
//promise (對(duì)應(yīng)上述promise ajax封裝形式)
ajax("http://vebcoder.cn:9527/api/getTypeOne")
.then(res=>{
console.log(JSON.parse(res))
})
.then(()=>{
return ajax("http://vebcoder.cn:9527/api/goodList")
})
.then(res=>{
console.log(JSON.parse(res))
})
//generator (對(duì)應(yīng)上述promise ajax封裝形式)
function* Gen(){
//請(qǐng)求成功開始下一步
ajax("http://vebcoder.cn:9527/api/getTypeOne").then(res=>{g.next(res)})
// 接收yield返回值
let res=yield;
console.log(res);
ajax("http://vebcoder.cn:9527/api/goodList").then(res=>{g.next(res)})
// 接收yield返回值
let res2=yield;
console.log(res2);
}
var g=Gen();
// 開始執(zhí)行代碼
g.next();
//async (對(duì)應(yīng)上述promise ajax封裝形式)
// 發(fā)送請(qǐng)求
;(async function(){
let res=await ajax("http://vebcoder.cn:9527/api/getTypeOne")
console.log(res)//請(qǐng)求的數(shù)據(jù)結(jié)果
let res2=await ajax("http://vebcoder.cn:9527/api/goodList")
console.log(res2)//請(qǐng)求的數(shù)據(jù)結(jié)果
}())
async
有更好的語(yǔ)義克胳,幾乎達(dá)到與同步代碼一樣的編程體驗(yàn)!
2019圈匆,不過(guò)是追求喜新厭舊的年頭漠另!