明白 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() {
    // 挪用 next('N') 时运转的代码
    console.log('0');
    let y1 = yield 1;
    return 1;                    // | 封装成 {value: 1, done: false} 返回
                                 // |
                                 // | 这两行等同于 let y1 = yield 1;
    // 挪用 next('I') 时运转的代码  // |
    let y1 = 'I';                // |
    console.log('1: ' + y1);
    return y1 + 2;               // | 封装成 {value: "I2", done: false} 返回
                                 // |
                                 // | 这两行等同于 let y2 = yield y1 + 2;
    // 挪用 next('L') 时运转的代码  // |
    let y2 = 'L';                // |
    console.log('2: ' + y2);
    return (y2 + 3);             // | 封装成 {value: "L3", done: false} 返回
                                 // |
                                 // | 这两行等同于 let y3 = yield (y2 + 3);
    // 挪用 next('S') 时运转的代码  // |
    let y3 = 'S';                // |
    console.log('3: ' + y3);
    return (y3);                 // | 封装成 {value: "S", done: false} 返回
                                 // |
                                 // | 这两行等同于 let y4 = (yield y3) + 4;
    // 挪用 next('H') 时运转的代码  // |
    let y4 = ('H') + 4;          // |
    console.log('4: ' + y4);
    return '??';                 // 封装成 {value: "??", done: true} 返回
    
    // done 为 true 以后, 再 next() 就都返回那一个了
}

再转头想想就知道了, 第一次运转 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 这类一个简朴的赋值都能玩出这么多名堂(固然, 这能够说是汗青遗留题目致使的)

老实说, 我以为这更多是为了: “别的言语有, 我们这么前卫的言语固然应当要有!”

就这么样一门言语, 竟然能够盛行成如今如许, 只能说这个天下是真巧妙

    原文作者:_nil
    原文地址: https://segmentfault.com/a/1190000018576234
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞