es6-async await 手寫(xiě) 前端進(jìn)階必備
雖然上次的表白計(jì)劃不了了之了,但我依然每天對(duì)她噓寒問(wèn)暖,我總相信,只要我對(duì)她好,總有一天我會(huì)感動(dòng)她的。我也開(kāi)始了所謂的舔狗之路......
一次和她的聊天中知道她喜歡吃大后街的一家早餐,但每天都起不來(lái)。然后我提出幫她帶早餐,起初她還覺(jué)得有點(diǎn)不好意思稍稍有拒絕的意思,后來(lái)在我一系列勸說(shuō)下答應(yīng)了,她答應(yīng)的那一刻,我高興的像個(gè)孩子,那是我們除同學(xué)之外的第一個(gè)交集,也給我無(wú)限的遐想和期望。
大后街還是有點(diǎn)遠(yuǎn)的,為了防止面條軟了,我也特意去買(mǎi)了輛自行車(chē),還記得第一次買(mǎi)早餐的時(shí)候,我給自己定了6點(diǎn)的鬧鐘,興奮、期待、緊張的我4點(diǎn)多就醒了,然后就毫無(wú)睡意了,腦子里一直在想等會(huì)應(yīng)該和她說(shuō)些啥,在哪里等她下來(lái).....
給她帶早餐的第六天,她說(shuō)她來(lái)那個(gè)了,下來(lái)不了了,她的室友幫她下來(lái)拿的,那時(shí)候的我對(duì)這方面真的不懂,我們那的人感覺(jué)都太保守了,對(duì)這種東西比較隱晦,于是我百度了一下,然后叮囑她多喝紅糖水,多休息之類的話。聊著聊著我就懷著好奇問(wèn)了一下她:“這大姨媽一個(gè)月來(lái)幾次哇?”。這句話也讓我成為了大學(xué)班上四年的笑話,至今還被他們提起.....
前言提示
各位掘友們,此篇文章需要從頭認(rèn)真往下閱讀,不然無(wú)法理解下文我通過(guò)生成器*函數(shù)和yield實(shí)現(xiàn)的async awit。認(rèn)真閱讀包你搞透async 生成器 迭代器這些知識(shí)點(diǎn)。
整理知識(shí)點(diǎn)不易,如果大家學(xué)到了,幫我點(diǎn)贊關(guān)注,后續(xù)我會(huì)繼續(xù)寫(xiě)進(jìn)階知識(shí)點(diǎn)。
迭代器、生成器、async
迭代器:迭代器是一種特殊對(duì)象,它具有一些專門(mén)為迭代過(guò)程設(shè)計(jì)的專有接口,所有的迭代器對(duì)象都有一個(gè)next()方法,每次調(diào)用都返回一個(gè)結(jié)果對(duì)象。結(jié)果對(duì)象有兩個(gè)屬性:一個(gè)是value,表示下一個(gè)將要返回的值;另一個(gè)是done,它是一個(gè)布爾類型的值,當(dāng)沒(méi)有更多可返回?cái)?shù)據(jù)時(shí)返回true。迭代器還會(huì)保存一個(gè)內(nèi)部指針,用來(lái)指向當(dāng)前集合中值的位置,每調(diào)用一次next()方法,都會(huì)返回下一個(gè)可用的值
如何區(qū)分是否能迭代
let arr=[1,2,3]let str='123'let obj={a:1,b:2}for(var i of arr){console.log('數(shù)組',i)}for(var i of str){console.log('字符串',i)}for(var i of obj){console.log('對(duì)象',i)}
打印結(jié)果如下圖

說(shuō)明:對(duì)象是不可迭代的
可以從原型去看一個(gè)類型是否支持迭代,以字符串為例
展開(kāi)字符串的原型,會(huì)發(fā)現(xiàn)它存在Symbol(Symbol.iterator)這個(gè)屬性,說(shuō)明它是可以迭代的。
把這個(gè)屬性用起來(lái),再結(jié)合迭代器的描述,你或許能進(jìn)一步理解迭代器。?
以?let str1='舔狗的淚'?為例

手動(dòng)實(shí)現(xiàn)一個(gè)迭代器效果 ? 以對(duì)象為例
var obj = {a: 1,b: 2,c: 3,[Symbol.iterator]() {var index = 0;let map = new Map([["a", 1],["b", 2],["c", 3],]);return {next() {let mapEntries = [...map.entries()];//將它還原成二維數(shù)組if (index < map.size) {return {value: mapEntries[index++],done: false,};} else {return { value: undefined, done: true };}},};},};let iter=obj[Symbol.iterator]()
測(cè)試下,同時(shí)會(huì)發(fā)現(xiàn)這個(gè)對(duì)象是能支持for of 的


遍歷和迭代的區(qū)別
迭代:從目標(biāo)源依次逐個(gè)抽取的方式來(lái)提取數(shù)據(jù)。目標(biāo)源是有序,連續(xù)
遍歷:只要能夠循環(huán)數(shù)據(jù),并不需要有序。
因?yàn)閷?duì)象循環(huán)不是有序的,所有它無(wú)法迭代,但是Map是可以支持迭代的。
生成器
函數(shù)前帶 * 表示生成器 ?用yield去產(chǎn)出它的值
function * test(){yield 1yield 2yield 3}var iter=test()iter.next()//輸出 {value:1,done:false}
iter也是可以通過(guò)for of循環(huán),這里不演示了
注意:每次調(diào)用next,他都會(huì)走到一個(gè)yield,下面代碼不會(huì)打印log
function * test(){console.log('舔狗的淚')yield 1yield 2yield 3}var iter=test()//要調(diào)用iter.next()才會(huì)走console.log
將生成器的yield 換成return 看看區(qū)別:

基于yield去改造剛才讓對(duì)象能夠迭代的方法
var?obj?=?{a: 1,b: 2,c: 3,[Symbol.iterator]:function * () {var index = 0;let map = new Map([['a', 1],['b', 2],['c', 3]]);let mapEntries = [...map.entries()]; //將它還原成二維數(shù)組while(indexyield mapEntries[index++]}}};let iter = obj[Symbol.iterator]();
對(duì)next方法傳參,看看yield丑陋的一面,async前世
function* test() {let value1 = yield 1;console.log('value1',value1);let value2 = yield 2;console.log('value2',value2);let value3 = yield 3;console.log('value3',value3);}var iter=test()iter.next('one')iter.next('two')iter.next('three')iter.next('')
結(jié)果分析:next里面的值會(huì)賦給上一次yield 的值 。
站在開(kāi)發(fā)者角度更期望 value1 打印的值就是1。async await它來(lái)了
async await基本操作
async await常見(jiàn)用法:let x=await 異步請(qǐng)求
看看它的其他用法,直接看圖說(shuō)話:
function b() {return new Promise(resolve => {setTimeout(() => resolve(1), 1000);});}async function a() {let value = await b();console.log(value);}a();//1秒后打印1
function b(){return 1}async function a() {let value = await b();console.log(value);}a();//打印1
function b() {let c = 1;}async function a() {let a = await b();console.log(a);}a();//打印undefined
基于* yield實(shí)現(xiàn)一個(gè)async
以下面例子去實(shí)現(xiàn)
let num=1//b函數(shù)只為模擬一個(gè)axiosfunction b() {return new Promise(resolve => {setTimeout(() => resolve(num++), 1000);});}async function a() {let value1 = await b();let value2 = await b();let value3 = await b();console.log(value1,value2,value3);return value3}let promise =a();//3秒后打印 1,2,3
基于生成器 遞歸實(shí)現(xiàn),需要先看上面的對(duì)next方法傳參,你才能明白下圖let num = 1;function b() {return new Promise(resolve => {setTimeout(() => resolve(num++), 1000);});}function* a() {let value1 = yield b();let value2 = yield b();let value3 = yield b();console.log(value1, value2, value3);return value3}function Co(iter) {//因?yàn)閍sync方法內(nèi)部包裹的就是Promise,所以這里也return一個(gè)Promisereturn new Promise((resolve, reject) => {let next = function (data) {let { value, done } = iter.next(data);if (done) {resolve(data);} else {//兼容b函數(shù)是一個(gè)非異步操作value instanceof Promise?value.then(val => {next(val);}, reject):next(value);}};next();});}let promise = Co(a());
個(gè)人理解及總結(jié)
迭代器:它的原型上面存在Symbol(Symbol.iterator),它可以被for of 循環(huán)
生成器:* 配合yield 的一個(gè)函數(shù)
如果你搞懂了生成器函數(shù),基于它實(shí)現(xiàn)async await就變得很容易了。
目前把es6里面的class Map Set Promise底層實(shí)現(xiàn)都寫(xiě)完了
源自:https://juejin.cn/post/7029100142208745503
聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請(qǐng)聯(lián)系小編刪除。
