這篇文章帶給大家的內容是關於es5中yield和es6中aysnc/await的介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
最近的業餘時間在看js 相關的書, 也在極客時間上買了前端相關的專欄, 對於一個非jser 的人來說, 時時會有一種感覺: js 社區是真的激進和浮燥, 這群規則的製定者似乎從來也不知道克制為何. 有很多時候固有的東西是可以處理好的, 但是偏偏喜歡人為製造一些概念和語法糖, 人為的建起一座又一座的高山, 似乎你沒跨過就是個"菜雞"
請原諒我的惡毒, 看《js 語言精粹》的時候, 這種感覺非常的強烈. 作者是業內的大牛, 還制定了json, 但是每一章還在最開頭引一句莎翁的話, "似乎無關緊要又暗藏哲理". 書中很多內容要表達的意思總有一種: 明明可以將話說成10 分讓一個普通人都能看得明白的, 卻偏不, 只說6 分, 剩下的自己去悟, 有很多規則性的東西並非是靠悟, 而是靠幾句話說清楚其本質就豁然開朗的.
換成以前, 會覺得這人是一座好大的高山要進行膜拜, 這幾年雖然自己技術依然不那麼好, 但是還是喜歡去思考一些內在的東西, 更在努力一點一點把心裡的權威崇拜給去掉, 再看到這些的時候, "..." 這幾個標點符號很容易印在腦子裡. 感覺這不只是一兩個人這樣, 極有可能是整個js 圈子都是這樣
說回標題上來, 除了看書, 看專欄, 找資料, 很久都還是沒有把generator 和async/await 給理解透, 於是自己試著整個梳理了一下運行的流程
我先試著在yield 後面不跟任何的東西, 可以直接複製到控制台輸出
function *f0(param) { console.log('n: ' + param); yield; console.log('i'); let l = yield; console.log('l: ' + l); } let v0 = f0('p'); console.log(v0.next(1)); // 输出 n: p 和 {value: undefined, done: false} console.log('----'); console.log(v0.next(2)); // 输出 i 和 {value: undefined, done: false} console.log('----'); console.log(v0.next(3)); // 输出 l: 3 和 {value: undefined, done: true} console.log('----'); console.log(v0.next(4)); // 输出 {value: undefined, done: true} console.log('----'); console.log(v0.next(5)); // 输出 {value: undefined, done: true}
在上面的基礎上給方法return 值
function *f1() { console.log('n'); yield; console.log('i'); let l = yield; console.log('l: ' + l); return '?'; } let v1 = f1(); console.log(v1.next(1)); // 输出 n 和 {value: undefined, done: false} console.log('----'); console.log(v1.next(11)); // 输出 i 和 {value: undefined, done: false} console.log('----'); console.log(v1.next(111)); // 输出 l: 111 和 {value: '?', done: true} console.log('----'); console.log(v1.next(1111)); // 输出 {value: undefined, done: true} console.log('----'); console.log(v1.next(11111)); // 输出 {value: undefined, done: true}
然後我試著在yield 的後面加上內容
function *f2(param) { console.log('0: ' + param); let f = yield 1; console.log('1: ' + f); let s = yield f + 2; console.log('2: ' + s); let t = yield (s + 3); console.log('3: ' + t); let fo = (yield s) + 4; console.log('4: ' + fo); } let v2 = f2('p'); console.log(v2.next('N')); // 输出 0: p 和 {value: 1, done: false} console.log('----'); console.log(v2.next('I')); // 输出 1: I 和 {value: "I2", done: false} console.log('----'); console.log(v2.next('L')); // 输出 2: L 和 {value: "L3", done: false} console.log('----'); console.log(v2.next('S')); // 输出 3: S 和 {value: "L", done: false} console.log('----'); console.log(v2.next('H')); // 输出 4: H4 和 {value: undefined, done: true} console.log('----'); console.log(v2.next('I')); // 输出 {value: undefined, done: true} console.log('----'); console.log(v2.next('T')); // 输出 {value: undefined, done: true}
最後, 在上面的基礎上給方法return 值
function *f3() { console.log('0'); let y1 = yield 1; console.log('1: ' + y1); let y2 = yield y1 + 2; console.log('2: ' + y2); let y3 = yield (y2 + 3); console.log('3: ' + y3); let y4 = (yield y3) + 4; console.log('4: ' + y4); return '??'; } let v3 = f3(); console.log(v3.next('N')); // 输出 0 和 {value: 1, done: false} console.log('----'); console.log(v3.next('I')); // 输出 1: I 和 {value: "I2", done: false} console.log('----'); console.log(v3.next('L')); // 输出 2: L 和 {value: "L3", done: false} console.log('----'); console.log(v3.next('S')); // 输出 3: S 和 {value: "S", done: false} console.log('----'); console.log(v3.next('H')); // 输出 4: H4 和 {value: "??", done: true} console.log('----'); console.log(v3.next('I')); // 输出 {value: undefined, done: true} console.log('----'); console.log(v3.next('T')); // 输出 {value: undefined, done: true}
大致上就清楚yield 的運行邏輯了, 以上面的f3 為例, 對照上面的輸出來看, 它其實是將一個方法分成了這樣幾段來執行
// 下面 五行一起的竖线(|) 用一个大括号表示出来会更直观一点 function *f3() { // 调用第 1 次 next('N') 时运行的代码 console.log('0'); let y1 = yield 1; return 1; // | 封装成 {value: 1, done: false} 返回 // | // | 这两行等同于 let y1 = yield 1; // 调用第 2 次 next('I') 时运行的代码 // | let y1 = 'I'; // | console.log('1: ' + y1); return y1 + 2; // | 封装成 {value: "I2", done: false} 返回 // | // | 这两行等同于 let y2 = yield y1 + 2; // 调用第 3 次 next('L') 时运行的代码 // | let y2 = 'L'; // | console.log('2: ' + y2); return y2 + 3; // | 封装成 {value: "L3", done: false} 返回 // | // | 这两行等同于 let y3 = yield (y2 + 3); // 调用第 4 次 next('S') 时运行的代码 // | let y3 = 'S'; // | console.log('3: ' + y3); return y3; // | 封装成 {value: "S", done: false} 返回 // | // | 这两行等同于 let y4 = (yield y3) + 4; // 调用第 5 次 next('H') 时运行的代码 // | let y4 = 'H' // | console.log('4: ' + y4); return '??'; // 封装成 {value: "??", done: true} 返回 }
再回頭想一想就知道了, 第一次運行next('N')的時候, 傳進去的N 是會被忽略的, 因為第一次next() 傳的值沒有yield 前面來接收. 再去看書也好, 看查到的文章也好, 第一次next() 都是沒有傳過參數
感覺yield 就是為了迭代而生的, 迭代完全可以就用for 啊, 但是卻繞成這樣, 也不知道這是為哪般! 就這還能新弄一個for of 玩出花來, 因為每執行next() 才會執行那一段段, 還美其名曰"咱們終於可以異步了"
再是es7開始有的這倆關鍵字, 看了一個大廠的面試題, 自己為了加深對這兩個關鍵字的理解改了一下成下面這樣
async function async1() { console.log('A'); console.log(await async2()); return 'B'; } async function async2() { console.log('C'); return 'D'; } console.log('E'); setTimeout(function() { console.log('F'); }, 0); async1().then(function(r) { console.log(r); }); new Promise(function(resolve, reject) { console.log('G'); resolve(); }).then(function() { console.log('H'); }); console.log('I');
在chrome 73.0.3683.75 底下的輸出是:
// 这个 undefined 的意思应该主要是用来分隔宏任务的, 也就是前面的主线和任务队列是在一起的 E A C G I D H B undefined F
在firefox 60.5.1 底下的輸出
// 这个 undefined 的意思应该只是用来分隔主线的, 任务队列和宏任务在一起了 E A C G I undefined H D B F
在opera 58.0.3135.107 底下的輸出是:
// 这个 undefined 应该跟 chrome 里面是一样的 E A C G I H D B undefined F
明顯D H B 是比較合理的. 在firefox 和opera 的實作中明顯是有問題的, 想像得到, 低版本一點的chrome 也可能是後面的結果
還有像var let const 這種一個簡單的賦值都能玩出這麼多花樣(當然, 這可以說是歷史遺留問題導致的)
老實說, 我覺得這更多是為了: "別的語言有, 咱們這麼前衛的語言當然應該要有!"
...
就這麼一門語言, 居然可以流行成現在這樣, 只能說這個世界是真奇妙
本篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的JavaScript教學影片欄位!
以上是es5中yield和es6中aysnc/await的介紹(附例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!