首頁 > web前端 > js教程 > 主體

es5中yield和es6中aysnc/await的介紹(附例)

不言
發布: 2019-03-20 10:21:14
轉載
3385 人瀏覽過

這篇文章帶給大家的內容是關於es5中yield和es6中aysnc/await的介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

最近的業餘時間在看js 相關的書, 也在極客時間上買了前端相關的專欄, 對於一個非jser 的人來說, 時時會有一種感覺: js 社區是真的激進和浮燥, 這群規則的製定者似乎從來也不知道克制為何. 有很多時候固有的東西是可以處理好的, 但是偏偏喜歡人為製造一些概念和語法糖, 人為的建起一座又一座的高山, 似乎你沒跨過就是個"菜雞"

請原諒我的惡毒, 看《js 語言精粹》的時候, 這種感覺非常的強烈. 作者是業內的大牛, 還制定了json, 但是每一章還在最開頭引一句莎翁的話, "似乎無關緊要又暗藏哲理". 書中很多內容要表達的意思總有一種: 明明可以將話說成10 分讓一個普通人都能看得明白的, 卻偏不, 只說6 分, 剩下的自己去悟, 有很多規則性的東西並非是靠悟, 而是靠幾句話說清楚其本質就豁然開朗的.

換成以前, 會覺得這人是一座好大的高山要進行膜拜, 這幾年雖然自己技術依然不那麼好, 但是還是喜歡去思考一些內在的東西, 更在努力一點一點把心裡的權威崇拜給去掉, 再看到這些的時候, "..." 這幾個標點符號很容易印在腦子裡. 感覺這不只是一兩個人這樣, 極有可能是整個js 圈子都是這樣

說回標題上來, 除了看書, 看專欄, 找資料, 很久都還是沒有把generator 和async/await 給理解透, 於是自己試著整個梳理了一下運行的流程

Generator

我先試著在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() 才會執行那一段段, 還美其名曰"咱們終於可以異步了"

async/await

再是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中文網其他相關文章!

相關標籤:
來源:segmentfault.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!