导航
写一个 generator 生成器 -> 调用后生成一个 迭代器 iterator
function * test(arr) {
for (const value of arr) {
yield value;
}
}
const iterator = test([1,2,3]);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
function generator(arr) {
let nextIdx = 0,
len = arr.length;
return {
next() {
return nextIdx < len
? { value: arr[nextIdx++], done: false }
: { value: undefined, done: true }
}
}
}
const iterator = generator([1,2,3]);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
为的是能够进一步执行后边中间件的逻辑,一旦当前中间件走不通,就不调用 next,从而阻断继续执行后续代码
;((functions) => {
function * generator(arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[i];
}
}
const iterator = generator(functions);
const init = () => {
nextDo(iterator.next());
}
function nextDo(n) {
n.value(function() { // 第一次迭代时,test1接收的参数next就是此处的匿名函数
const n = iterator.next();
if (!n.done) {
nextDo(n);
} else {
return;
}
});
}
init();
})([
function test1(next) {
console.log('test1');
console.log(next); //这里的next就是上边 n.value 中的匿名函数
next();
},
function test2(next) {
console.log('test2');
next();
},
function test3(next) {
console.log('test3');
next();
},
function test4(next) {
console.log('test4');
next();
},
function test5(next) {
console.log('test5');
next();
},
]);
;((functions) => {
function * generator(arr) {
for (let i = 0; i < arr.length; i++) {
const func = arr[i];
yield func;
}
}
const iterator = generator(functions);
const init = () => {
nextDo(iterator.next());
}
function nextDo(n) {
n.value(function() { // 第一次迭代时,test1接收的参数next就是此处的匿名函数
const n = iterator.next();
if (!n.done) {
nextDo(n);
} else {
return;
}
});
}
init();
})([
function test1(next) {
console.log('test1');
let username = '233'
if (username.length > 6) {
next();
}
},
function test2(next) {
console.log('test2');
next();
},
function test3(next) {
console.log('test3');
next();
},
function test4(next) {
console.log('test4');
next();
},
function test5(next) {
console.log('test5');
next();
},
]);
;(function(doc) {
function Log() {
this.oInput = doc.getElementsByTagName("input")[0];
this.oBtn = doc.getElementsByTagName("button")[0];
this.oList = doc.getElementsByClassName("logs")[0];
this.logs = [];
this.iterator = generator(this.logs);
this.init();
}
Log.prototype.init = function() {
this.bindEvent();
}
Log.prototype.bindEvent = function() {
this.oBtn.addEventListener('click', handleBtnClick.bind(this), false);
}
function handleBtnClick(e) {
const val = this.oInput.value;
this.logs.push({
date: new Date(),
value: val,
})
_addLog.call(this, this.iterator.next().value);
}
function _addLog(log) {
const oLi = doc.createElement("li");
oLi.innerHTML = `
操作内容: ${log.value}
操作时间: ${log.date}
`;
this.oList.appendChild(oLi);
}
function * generator(arr) {
for (const value of arr) {
yield value;
}
}
window.Log = Log;
})(document);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>日志打印</title>
</head>
<body>
<div class="container">
<input type="text" placeholder="输入操作">
<button>执行</button>
<ul class="logs"></ul>
</div>
<script src="./index.js"></script>
<script>
new Log();
</script>
</body>
</html>
generator + co异步迭代函数 === async函数 + await
generator生成器函数 + yield + co === async + await => 语法糖
generator2.js
const fs = require('fs').promises; // promise化fs下所有异步方法
function * getUserClasses(uid) {
// 返回一个promise,看到yield就停止了,下次next才会把这次yield产出值赋值给userDatas
let userDatas = yield fs.readFile('./data/user.json', 'utf-8');
userDatas = JSON.parse(userDatas);
const userData = userDatas.find(user => user.id === uid);
let classDatas = yield fs.readFile('./data/class.json', 'utf-8');
classDatas = JSON.parse(classDatas);
let userClassData = {
id: userData.id,
name: userData.name,
classes: []
};
classDatas.map(c => {
const studentsArr = JSON.parse(c.students);
studentsArr.map(s => {
if (s === uid) {
userClassData.classes.push({
id: c.id,
name: c.name
});
}
});
});
return userClassData;
}
module.exports = {
getUserClasses
}
// 最终期望的结果
// [
// {
// "id": 1,
// "name": "蕾姆",
// classes: [
// {
// "id": 1,
// "name": "前端"
// },
// {
// "id": 2,
// "name": "后端"
// }
// ]
// }
// ]
index2.js
const { getUserClasses } = require('./generator2');
const uid = 1;
const it = getUserClasses(uid);
const { value, done } = it.next();
value.then(res => {
const { value, done } = it.next(res);
value.then(res => {
const { value, done } = it.next(res);
console.log(value)
});
});
// {
// id: 1,
// name: '雷姆',
// classes: [ { id: '1', name: '前端' }, { id: '2', name: '后端' } ]
// }
太繁琐,又是个回调地狱。
getUserClasses(uid).then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
generator2.js
...
function co(iterator) { // 异步迭代函数
// co最终要.then拿到最终值,所以要return一个promise实例
return new Promise((resolve, reject) => {
// 迭代器递归函数 参数:传给next的数据
function walk(data) {
// 执行 next => value done 对象
const { value, done } = iterator.next(data);
if (!done) {
// value 有可能不是个 Promise,为了能往下走,再用 Promise.resolve 包一下
// value -> then -> 拿到新的迭代时 程序执行的结果
Promise.resolve(value).then(res => {
// 肯定要继续执行迭代器递归函数
walk(res);
// promise出错了 -> 本次返回的Promise的reject
}, reject);
} else {
// done === true,迭代结束,成功抛出value
resolve(value);
}
}
walk();
});
}
...
index2.js
const { getUserClasses, co } = require('./generator2');
const uid = 1;
co(getUserClasses(uid)).then(res => {
console.log(res);
});
// {
// id: 1,
// name: '雷姆',
// classes: [ { id: '1', name: '前端' }, { id: '2', name: '后端' } ]
// }
generator2.js
async function asyncGetUserClasses(uid) {
// 返回一个promise,看到yield就停止了,下次next才会把这次yield产出值赋值给userDatas
let userDatas = await fs.readFile('./data/user.json', 'utf-8');
userDatas = JSON.parse(userDatas);
const userData = userDatas.find(user => user.id === uid);
let classDatas = await fs.readFile('./data/class.json', 'utf-8');
classDatas = JSON.parse(classDatas);
let userClassData = {
id: userData.id,
name: userData.name,
classes: []
};
classDatas.map(c => {
const studentsArr = JSON.parse(c.students);
studentsArr.map(s => {
if (s === uid) {
userClassData.classes.push({
id: c.id,
name: c.name
});
}
});
});
return userClassData;
}
index2.js
const { getUserClasses, co, asyncGetUserClasses } = require('./generator2');
const uid = 1;
asyncGetUserClasses(uid).then(res => {
console.log(res);
});
// {
// id: 1,
// name: '雷姆',
// classes: [ { id: '1', name: '前端' }, { id: '2', name: '后端' } ]
// }
generator + co异步迭代函数 === async函数 + await
generator生成器函数 + yield + co === async + await => 语法糖
function generatorToAsync(generatorFn) {
return function() {
const gen = generatorFn.apply(this, arguments) // gen有可能传参
// 返回一个Promise
return new Promise((resolve, reject) => {
function go(key, arg) {
let res
try {
res = gen[key](arg) // 这里有可能会执行返回reject状态的Promise
} catch (error) {
return reject(error) // 报错的话会走catch,直接reject
}
// 解构获得value和done
const { value, done } = res
if (done) {
// 如果done为true,说明走完了,进行resolve(value)
return resolve(value)
} else {
// 如果done为false,说明没走完,还得继续走
// value有可能是:常量,Promise,Promise有可能是成功或者失败
return Promise.resolve(value).then(val => go('next', val), err => go('throw', err))
}
}
go("next") // 第一次执行
})
}
}
使用:
function* gen() {
const num1 = yield fn(1)
console.log(num1) // 2
const num2 = yield fn(num1)
console.log(num2) // 4
const num3 = yield fn(num2)
console.log(num3) // 8
return num3
}
const genToAsync = generatorToAsync(gen)
const asyncRes = genToAsync()
console.log(asyncRes) // Promise
asyncRes.then(res => console.log(res)) // 8