1. generator
- generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数(但并不是一个函数),但可以返回多次;
- generator由function定义(注意多出的号),并且,除了return语句,还可以用yield返回多次;
- next()方法会执行generator的代码,然后,每次遇到yield 语句;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果done为true,则value就是return的返回值;
// 生成器的声明
function* gen() {
console.log('abc');
console.log('1');
console.log('2');
console.log('3');
// 礼让 => 异步
let res = yield 'Green';
//下面打印的res就是yield返回的'Green'
console.log('444', res) // 444 Green
console.log('555')
}
// 获取生成器对象
let generator = gen();
let res = generator.next();
console.log(res); // {value: 'Green', done: false}
generator.next(res.value);
2. async-await(ES2017)
- async-await是ES2017(ES8)提出的基于Promise的解决异步的最终方案,现在更为常用;
- async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。因此对async函数可以直接then,返回值就是then方法传入的函数。
- await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待;
- await 修饰的如果是Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;
- 如果不是Promise对象:把这个非promise的东西当做await表达式的结果;
// 看似同步代码
async function asyncFn() {
console.log('3');
// await可以控制异步
let res = await new Promise(res => {
console.log('5');
res('数据abc');
})
// 不调用res('数据abc'); 则不执行后续代码
// 等同于.then里面的代码
console.log('4', res); // 也就是说不调用res('数据abc'),本句打印代码不会执行
}
// 同步优先
console.log('1')
asyncFn();
2.1 async-await应用--处理没有try的reject异常
原理是参数错误优先规则,自定义一个pretty函数来对promise对象进行预处理
function pretty(promise) {
// 中间层处理 , 参数错误优先
return promise.then(res => {
return [undefined, res];
})// 处理过以后fulfilled
.catch(err => {
return [err, undefined];
})// 处理过以后fulfilled
}
使用场景,处理没有try的reject异常
const { log: l } = console;
function req() { // 去解决,拒绝
return new Promise((resolve, reject) => {
setTimeout(() => {
// 数据回来了
let data = Math.random();
if (data < 0.5) return reject(data)
else return resolve(data); // 调用20行的参数,函数
}, 1000);
})
}
// 在run函数使用自定义pretty函数,并配合async-await实现功能
async function run() {
let [err, data] = await pretty(req());
if (err) return console.log('错误了', err)
console.log('成功,数据是:', data)
var res = await req()
l('成功')
}
run(); // 调用run函数进行测试
也可以使用以下方法处理没有try的reject异常
window.addEventListener('unhandledrejection', (err) => {
err.preventDefault();
// reject(参数)
console.log(err.reason, '错误了');
});
3. async-await在forEach循环里的应用
使用场景,想要实现每隔1s调用一次函数fn
let arr = [1, 2, 3, 4, { name: 'Green', fn() { } }]
const { log: l } = console;
function req(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(n);
}, 1000);
})
}
arr.forEach(async (ele, index, newArr) => {
await req(ele);
console.log('响应了...', ele, newArr)
})
结果只等待1s就全部响应完毕
重写forEach进行优化
// 覆盖forEach方法
Array.prototype.forEach = async function (fn) {
// 健壮性判断
if (typeof fn !== 'function') throw new Error('必须传递函数');
// 判断this是数组
if (!Array.isArray(this)) throw new Error('this必须是一个数组');
for (let i = 0, len = this.length; i < len; i++) {
// 自己的方法
await fn.call(this, this[i], i, this);
}
}