前言
async,await的简单使用在这里就不再赘述,前端的很多痛点在es6,es7中已经被一两个关键词就可以解决了,但最终很多时候被babel转化为es5的语法。
作为一个日常CV前端,我想多了解一点关于它的知识也许某一天可以少一个通宵呢 ╮( ̄▽ ̄)╭
Generator 的碎碎念
相关方法
Generator.prototype.next() 返回一个由 yield表达式生成的值
Generator.prototype.return() 返回给定的值并结束生成器
Generator.prototype.throw() 向生成器抛出一个错误
基础用法
function* gen() {
try {
let first = yield 1;
let second = yield first + 2;
yield second + 3;
} catch (e){
console.log(e);
}
}
var iterator = gen();
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next(4)); // {value: 6, done: false}
console.log(iterator.next()); // {value: NaN, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
console.log(iterator.return(); // { value: undefined, done: true }
console.log(iterator.return(1); // { value: 1, done: true }
iterator.throw('出错了'); //出错了
如果以以上的答案都能答对,恭喜你基础知识已经都掌握了。
Object 与... ,for of
一个数据结构只要部署了Symbol.iterator属性就能使用 for...of遍历 与 ...运算符 操作
Object身上没有Symbol.iterator,当直接使用时会报错
let obj = {
0: 'a',
1: 'b',
2: 'c',
}
for(let p of obj){
console.log(p);//TypeError: obj is not iterable
}
所以需要在Object上添加一个生成器方法
console.log([ // ... Array.from
...{
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]:function *(){
let index = 0;
while(index !== this.length){
yield this[index++];
}
}
// [Symbol.iterator]() {
// let len = this.length;
// let index = 0;
// //迭代器 是有next方法 而且方法执行后 需要返回 value,done
// return {
// next: () => {
// return { value: this[index++], done: index === len + 1 };
// }
// };
// }
}
]);
Regenerator 转换器
Generator 编译成低版本可用大致流程为,编译阶段需要处理相应的抽象语法树(ast),生成符合运行时代码的 es5 语法结构。运行时阶段,添加 runtime 函数辅助编译后语句执行。
regenerator 网站 提供可视化操作,简单 ast 转码前后示例如下:
function *range(max, step) {
var count = 0;
step = step || 1;
for (var i = 0; i < max; i += step) {
count++;
yield i;
}
return count;
}
var gen = range(20, 3), info;
while (!(info = gen.next()).done) {
console.log(info.value);
}
console.log("steps taken: " + info.value);
转换后
ar _marked =
/*#__PURE__*/
regeneratorRuntime.mark(range);
function range(max, step) {
var count, i;
return regeneratorRuntime.wrap(function range$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
count = 0;
step = step || 1;
i = 0;
case 3:
if (!(i < max)) {
_context.next = 10;
break;
}
count++;
_context.next = 7;
return i;
case 7:
i += step;
_context.next = 3;
break;
case 10:
return _context.abrupt("return", count);
case 11:
case "end":
return _context.stop();
}
}
}, _marked);
}
var gen = range(20, 3),
info;
while (!(info = gen.next()).done) {
console.log(info.value);
}
console.log("steps taken: " + info.value);
async,await出现前,优秀的解决异步问题的co库
co 是 TJ大神 于 2013 年推出的一个利用 ES6 的 Generator 函数来解决异步操作的开源项目,百行的代码很适合入门阅读。
关键部分
/**
* Execute the generator function or a generator
* and return a promise.
*
* @param {Function} fn
* @return {Promise}
* @api public
*/
function co(gen) {
//暂存上下文
var ctx = this;
//Array.prototype.slice 除去传来的方法名留下参数
var args = slice.call(arguments, 1);
// we wrap everything in a promise to avoid promise chaining,
// which leads to memory leak errors.
// see https://github.com/tj/co/issues/180
//co()返回Promise对象
return new Promise(function(resolve, reject) {
//执行一次Generator获取遍历器
if (typeof gen === 'function') gen = gen.apply(ctx, args);
if (!gen || typeof gen.next !== 'function') return resolve(gen);
//执行成功回调函数
onFulfilled();
/**
* @param {Mixed} res
* @return {Promise}
* @api private
*/
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
return null;
}
/**
* @param {Error} err
* @return {Promise}
* @api private
*/
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}
/**
* Get the next value in the generator,
* return a promise.
*
* @param {Object} ret
* @return {Promise}
* @api private
*/
//此处为精华所在,连续执行next
function next(ret) {
//generator执行完毕
if (ret.done) return resolve(ret.value);
//每次都将yield后的值转换为promise
var value = toPromise.call(ctx, ret.value);
//使用promise.then连续调用
//onFulfilled, onRejected会继续调用next本身
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
//yield后的值无法转换为promise的情况
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
+ 'but the following object was passed: "' + String(ret.value) + '"'));
}
});
}
async,await
async,await 函数是什么?一句话,它就是 Generator 函数的语法糖。