始
近来的业余时刻在看 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 这类一个简朴的赋值都能玩出这么多名堂(固然, 这能够说是汗青遗留题目致使的)
老实说, 我以为这更多是为了: “别的言语有, 我们这么前卫的言语固然应当要有!”
…
就这么样一门言语, 竟然能够盛行成如今如许, 只能说这个天下是真巧妙