為什么會(huì)出現(xiàn)異步
js是一門為瀏覽器而誕生的語言,發(fā)展到現(xiàn)在,js已經(jīng)不僅僅只在瀏覽器上運(yùn)行了,服務(wù)端也可以運(yùn)行js,像node。而js最初設(shè)計(jì)是單線程,也就是說會(huì)一行一行的執(zhí)行,下面需要等待上面代碼執(zhí)行完畢,也就是說在特定的時(shí)刻只能做特定的事情,阻塞其他代碼的執(zhí)行。
常用的異步例如網(wǎng)絡(luò)請(qǐng)求、讀取文件等。
異步解決方案
了解javascript為什么會(huì)出現(xiàn)異步,那么我們?cè)撛趺慈ソ鉀Q異步呢?如何書寫日常工作中的工程代碼呢?javascript的演變中出現(xiàn)了如下幾種解決方案。
callback
一般在網(wǎng)絡(luò)請(qǐng)求中我們并不知道服務(wù)端啥時(shí)候返回結(jié)果,在這個(gè)等待的過程中,我們不能讓頁面一直卡頓或是不能操作的狀態(tài),這樣會(huì)給用戶很不好的體驗(yàn)感覺,我們又需要在服務(wù)端返回結(jié)果的時(shí)候來進(jìn)行相應(yīng)的操作或是數(shù)據(jù)更新。于是回調(diào)函數(shù)就成為異步的第一個(gè)解決方案,如下:
$.ajax({
? ? "url": "",
? ? success: function(data){
? ? ?//函數(shù)返回成功需要進(jìn)行的操作或數(shù)據(jù)更新
? ? },
? ? error: function(err){
? ? //函數(shù)返回失敗需要進(jìn)行的操作或提示
? ?}
})
這是在jq中我們非常熟悉的一個(gè)操作,當(dāng)我們?nèi)フ?qǐng)求服務(wù)端時(shí),不管成功或失敗,服務(wù)端都會(huì)返回一個(gè)結(jié)果,success和error函數(shù)就是一個(gè)callback函數(shù),不管成功或是失敗,我們都能進(jìn)行相應(yīng)的操作或是提示,在網(wǎng)絡(luò)請(qǐng)求的過程中,并不影響用戶對(duì)別的操作(除非不想讓用戶操作,必須要等待這個(gè)操作完成),當(dāng)服務(wù)端返回?cái)?shù)據(jù)時(shí),我們可以通過callback接收到,這個(gè)時(shí)候我們?cè)龠M(jìn)行相應(yīng)的操作。
Promise
在callback中,如果當(dāng)前網(wǎng)絡(luò)請(qǐng)求需要依賴前一個(gè)網(wǎng)絡(luò)請(qǐng)求,我們就有可能掉進(jìn)回調(diào)地獄,
如圖:

于是promise的出現(xiàn)為我們解決了這個(gè)問題。promise是在ES6中被統(tǒng)一規(guī)范,由瀏覽器直接支持,promise為一諾千金的意思,意思是在將來不管這個(gè)狀態(tài)成功或是失敗,都將返回一個(gè)結(jié)果。
promise有三種狀態(tài):
等待中? pending;
已完成? fulfilled;
已拒絕? reject;
let test = new promise(resolve,reject){
? ? ? if(success){
? ? ? ? ?resolve();
? ? ? }else{
? ? ? ? reject();
? ? ? }
? }
test()
.then(res => {
? ?//成功時(shí)返回函數(shù)
})
.catch(err => {
? //失敗時(shí)返回函數(shù)
})
Generator
我們希望以同步方式寫異步代碼,可以使邏輯清晰,代碼簡(jiǎn)潔,為了實(shí)現(xiàn)這種目的,我們又演進(jìn)出generator方案,
function * add(x){
? ?yield? x + 50;
? ?yield x + 100;
? ?return x + 150;
}
let? test = add(5);
test.next(); //done: true , value: 55
test.next(); //done: true , value: 105
test.next(); //done: true , value: 155
如上,genertor與普通函數(shù)區(qū)別不大,function后面加了一個(gè)*,
首先定義了一個(gè)test = add(5),函數(shù)沒有執(zhí)行,只是生成了一個(gè)genertor對(duì)象,函數(shù)屬于暫停狀態(tài),只有當(dāng)執(zhí)行.next()時(shí),才會(huì)激活暫停狀態(tài),開始執(zhí)行內(nèi)部代碼,遇到第一個(gè)yield才會(huì)返回執(zhí)行結(jié)果,并記住上下文,暫停,交出控制權(quán),再次執(zhí)行,找到第二個(gè)yield,并重復(fù)上述步驟
function* Fn(){
? var result = yield ajax(url);
var result1 = yield ajax(url1);
}
let F = Fn();
var result = F.next();
result.value
.then(res => {
? ?F.next();
})
.catch(err => {
})
如上 封裝一個(gè)ajax異步,定義一個(gè)genertor對(duì)象,執(zhí)行請(qǐng)求交出控制權(quán),根據(jù)返回結(jié)果執(zhí)行第二個(gè)ajax請(qǐng)求
asnyc/await
ES7的asnyc/await號(hào)稱是異步的終極解決方案,讓我們以同步的方式來書寫異步代碼,這樣看起來更簡(jiǎn)潔,邏輯更清晰。
比如微信小程序煩人的異步:
const Login =? data => {?
? return new Promise( (resolve, reject) => {?
? ? wx.login({?
? ? ? success: res => {?
? ? ? ? ?resolve(res);
? ? ? ?},?
? ? ? ?fail: err => {??
? ? ? ? ? reject(err);?
? ? ? ? }?
? ? ? })?
? ?})?
}
const getUserInfos = data => {
? return new Promise((resolve,reject){
? ? wx.getUserInfo({
success: res => {
? ? ? ?resolve(res);
? ? ? },
? ? ?fail: err => {?
? ? ? ?reject(err);
? ? ?}?
? ? })
? })
}
const sendCode = data = > {
? return new Promise((resolve,reject){
? ? ?wx.request({
? ? ? ?url: '',
? ? ? ?success: res=> {
? ? ? ? ? ?resolve(res);
? ? ? ?},
? ? ? ?fail: err => {
? ? ? ? ? reject(err);
? ? ? ?}
? ? ?})
? })
}
以上就是封裝好的微信登錄過程中的獲取code userInfo 和發(fā)送ajax請(qǐng)求的幾個(gè)函數(shù),
然后
asycn function getLogin(){
?try {
? let result_login? =? await Login();
? let result_userInfo = await getUserInfos();
result_userInfo['code'] = result_login['code'];
? let result_sendCode = await sendCode(result_userInfo );
? return result_sendCode;
?}catch(err){
?console.log(err);
}
}
getLogin()
.then(res => {
})
.catch(err => {
}
async與genertor的寫法類似,具備更好的語義,并且返回的是promise
作者:lzksdxh
鏈接:https://juejin.im/post/5af8f706f265da0b8f62a7d1
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。