[完結篇] - 理解異步之美 --- promise與async await (三)

天下沒有不散的宴席

**這個系列到這裏應該就是最後一節了,**前兩章着重講了promise,爲何着重講promise呢?由於在用法上promise要比async await難一些,並且promise自己又不是一個語法糖。沒有掌握的時候用起來就會有不少顧慮,async await卻沒有這種顧慮,用法簡單、語義清晰。javascript

基礎預熱:你好,JavaScript異步編程---- 理解JavaScript異步的美妙前端

理解異步之美:Promise與async await(一)vue

理解異步之美:Promise 與 async await(二)java

下面就要開始學習async await了面試

不講講迭代器模式總以爲怪怪的

對於java語言來講,迭代器是一個很基本的模式,list與set結構都內置了迭代器。ajax

可是javascript並無這種結果(ps:ES6提供了set,並且也能夠實現迭代器),可是咱們對這種模式實用的並非特別多。 迭代器模式是指提供一種方法順序訪問一個聚合對象中的各個元素,而又不須要暴露該對象的內部表示。編程

so:迭代器就是在不暴露對象的內部表示的狀況下,可以遍歷整個元素promise

核心嘛就是:不暴露內部,能夠遍歷內部異步

下面咱們就來實現一個簡單的迭代器async

// 在數據獲取的時候沒有選擇深拷貝內容,
// 對於引用類型進行處理會有問題
// 這裏只是演示簡化了一點
function Iterdtor(arr){
	let data = [];
    if(!Array.isArray(arr)){
        data = [arr];
    }else{
        data = arr;
    }
    let length = data.length;
    let index = 0;
    // 迭代器的核心next
    // 當調用next的時候會開始輸出內部對象的下一項
    this.next = function(){
    	let result = {};
    	result.value = data[index];
    	result.done = index === length-1? true : false;
    	if(index !== length){
            index++;
            return result;
    	}
    	// 當內容已經沒有了的時候返回一個字符串提示
    	return 'data is all done'
    };
}
let arr = [1,2,3,4,5,6];
// 生成一個迭代器對象。
let iterdtor = new Iterdtor(arr);
iterdtor.next()
iterdtor.next()
複製代碼

這就符合迭代器模式的特色,並無暴露內部的對象, 經過next的方法能夠遍歷內部對象。

說到如今不少人應該還沒理解爲何要說迭代器。

Generator函數執行後會返回一個迭代器

async函數是Generator的語法糖

這兩個理由是否是一會兒就說明寫迭代器是頗有用處的。

書寫一個簡單的Generator函數

function *Iterdtor(){
	console.log(1);
	yield '123';
	console.log(2);
	yield '234';
	console.log(3);
	return '345'
}
let iterator = Iterdtor();
複製代碼

咱們執行了一下Generator函數返回一個迭代器。經過next方法,能夠阻塞性的去執行Generator的代碼。

一說到阻塞你們就想到同步等待阻塞線程致使頁面十分卡頓,明明不是一件很好的事情,爲何要用這種東西呢?

下面咱們就聊聊這種阻塞性的方式有什麼好處呢?

在Generator函數中,迭代器調用next函數後,會一直執行到有yield標示的位置中止。等待next的下一次調用後,代碼會繼續執行到下個yield表示。沒有yield的話就一執行到最後return的位置(沒有return就會一直執行完全部的代碼,這句話好像是個廢話)。

代碼就像擠牙膏同樣,擠一點出一點擠一點出一點,最後沒有卡頓的地方,一口氣擠到底。

因此說若是實用Generator的方式來處理異步的請求會是怎樣的一種感受。

// 僞代碼
let ajaxSign = false;
function *ajaxGetSomething(){
    ajaxSomethingOne().then(res=>{ajaxSign = true})
    yield
    ajaxSign = false;
    ajaxSomethingSecond().then(res=>{ajaxSign = true})
}
let iterator = ajaxGetSomething();
iterator.next();
while(ajaxSign){
    iterator.next()
}
複製代碼

若是以這種方式來實現異步的請求會怎樣,

1:有一個標誌表明ajax請求完成。

2:當標誌爲true時表明ajax執行完成,能夠進行下一個事件了。

3:當標誌爲false代碼ajax還未執行完成,繼續阻塞下面的代碼。

4:當第一個標誌爲true時,執行next(),而後發現到下一個yield之間有異步的代碼,將標誌設置爲false,開始執行ajax的事情,阻塞着後面的內容。

5:當ajax完成後把標誌設置爲true,開始2的內容作的事情不斷執行着直到整個迭代器完成。

粗俗的while循環實現next的調用是不可取的(畢竟僞代碼)

這種方式讓咱們體會到另外一種處理異步的方式,就是阻塞時的去執行多個串行的異步任務,這樣能夠感覺同步的寫法去書寫異步的代碼,也就不會在不合適的時間去拿去異步的產生的數據,你阻塞着線程,你不等他執行完,你取值的操做也作不了呀。

如何實用async await

說到這裏如何使用他們就比較清晰明瞭了吧

async function ajaxGetData(){
    xxxx
    dosomething()
    await ajaxGetDataFirst()
    dosomething()
    await ajaxGetDataSecond()
    dosomething()
    xxx
}
ajaxGetData()
複製代碼

這個時候咱們使用async函數來處理異步效果就很清晰了,

咱們作了一些事情,而後到一個異步的ajax請求後,等待ajaxGetDataFirst這個異步的事件執行完畢後,開始繼續作一些事情,到了第二個ajax異步請求ajaxGetDataSecond(),開始執行阻塞住函數的執行,等待異步事件執行完畢後就繼續作下面的事情。用await關鍵字的時候就是在告訴下面的代碼,這塊你得給我等着,wait我執行完了才能輪到你 understand?總之await吊極了。

await在何時能夠用? 只有在async函數體內部使用,並且這個做用範圍是不能夠繼承下去的。

在promise中怎麼使用async函數

new Promsie(async (resolve,reject)=>{
     await xxx
 })
 // 這樣的async才能使await有效果,書寫在promise以外的話await就會像上面同樣報錯
複製代碼

await 能夠接收一個同步的事情嗎?繼續執行下去不阻塞

async函數的返回值是什麼? async函數的返回值是一個promise對象,

???? what 返回了一個promise對象。這有啥用呢?請聽下面分析 這就表明着你在執行完全部的異步請求後還能夠繼續將你須要的結果用return的方式保存在一個promise對象中。promise的用處是什麼?他好像能夠存儲一個值在指定狀況下觸發一個回調函數(這個不理解的能夠看一下上一篇內容哈)因此這能夠幫助咱們把內部的異步請求的數據拋出到函數外部來。

下面的使用場景:

在使用場景中,咱們有的時候須要異步的一個結果,好比ajax請求的結果,這個時候咱們但願獲得這個異步的結果怎麼辦? 這個時候await能夠幫助我,在執行完異步的操做的時候拿到結果,在拿到結果後順序執行下去。直到return的時候把這個結果 return出去,

如下兩種寫法咱們是均可以使用的

async function fn(){
	let result = await new Promise((resolve,reject)=>{
		setTimeout(()=>{
            resolve(100)
		},10000)
	}).then(res=>{
			return res
		})
	return result
}
let a = fn()
複製代碼
async function fn(){
	let result = await new Promise((resolve,reject)=>{
		setTimeout(()=>{
            resolve(100)
		},10000)
	})
	return result
}
let a = fn()
複製代碼

這兩種方式均可以等待異步的promise執行完成以後再賦值給result,這個時候,咱們返回的a就是一個pending狀態的promise對象,上一章節咱們講過了promise的基本原理,後面的操做我就很少提了,因此獲得你想要的內容的promsie你就會操做了。

這個時候咱們async內的異步操做的結果天然而然的能夠拋出到函數外部來使用,能夠解決不少的業務的封裝問題了。

async 與 Generator的區別

async 與Generator的區別是什麼?

async是Generator的語法糖,Generator是能夠用來實現async的,用Generator來實現async的核心就是實現這種不需next調用自執行的內容,這是我之後要進行學習的(目前時間不是很充裕,打算學好以後出一個特別篇好好實現如下async)

尾聲咯

這一節內容並無講不少async的內容,反而是先講了迭代器,再講了Generator,最後對async的使用簡單介紹了一下,這是我在學習async時的順序,async用起來容易、同步的寫法也比較熟悉,but!!!易用的東西每每表明着方法內部蘊含不少你不知道的東西, 這纔是咱們要挖掘的AV8D!!!!

總結一下

異步的事情咱們理解了,異步程序執行的過程,瞭解了event table,任務隊列,宏任務微任務的執行前後條件。瞭解了異步promise的用法,promise的實現機制、async的用法,以及衍生出來的迭代器知識。

這一段時間和邊學習邊產出文章,有一種被你們鞭策的感受,哈哈哈哈哈。鞭策這個詞有點怪怪的,這個過程當中我發現學習不能只有興趣,興趣能夠幫你研究你喜歡的內容時有無限的動力,上了發條同樣,在你低谷、沒有興趣的時候還須要鞭策來幫你去學習新的不擅長的知識,

之前異步是我掌握最差的部分,在這一個階段的學習我收穫不少不知道身爲讀者的你收穫了多少呢? 只有你本身知道了

有結束也有開始

異步的美妙咱們就算是先告一段落。

下面的一個巨大的系列章節,我將會對vuer-router源碼進行一個系統的學習,而且隨着學習之中產出文檔喲,算是繼續鞭策和與你們一塊學習。 仍是那個熟悉的結束語:每個前端coder(boy and girl)大家永遠不是一我的在戰鬥~

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,已經咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索