ES6-20 iterator与generator
ES6-21 async与await、ES6的模块化
try catch不能捕获异步异常
- try catch是同步代码
try {
setTimeout(() => {
console.log(a)
})
} catch (e) {
console.log(e)
}
iterator
内部迭代器:系统定义好的迭代器接口(如数组Symbol.iterator)
外部迭代器:手动部署(可以给obj定义外部迭代器)对于遍历器对象来说,done: false和value: undefined属性都是可以省略的
内部迭代器:
- 除了next之外还可以增加
return(){}
,在for…of循环中凡是使用break或者throw new Errow()来终止循环的,会走return
let obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]() {
let nextIndex = 0
let map = new Map()
for (let [key, value] of Object.entries(this)) {
map.set(key, value)
}
let mapEntries = [...map.entries()],
len = mapEntries.length
return {
next() {
return nextIndex < len ?
{ value: mapEntries[nextIndex++], done: false } :
{ value: undefined, done: true }
}
}
}
}
for (let i of obj) {
console.log(i)
}
// ["a", 1]
// ["b", 2]
// ["c", 3]
默认调用iterator接口
...
for...of
Array.from()
map\set
Promise.all() Promise.race()
yield
generator
- 生成器
- 用于返回迭代器对象
- yield只能出现在生成器中
- yield执行的返回值是undefined(并不产生值)
- 结合yield使用,能结合next拿到
- yield暂停代码运行,有记忆功能
- return代码终止
- 不调用next时,不会运行test内的代码
function * test(){
yield 'a'
console.log('第二次调用next时才打印')
yield 'b'
yield 'c'
return 'd'
}
let iter = test()
// 不调用next时,不会运行test内的代码
console.log(iter.next()) // 暂停
console.log(iter.next())
console.log(iter.next())
console.log(iter.next()) // 终止 done为true了
- 打印iter
return
- 终止迭代,done为true,value取决于是否有返回值
- 内部return
function* test() {
yield 1;
return;// 再次调用next,return之后value都是undefined
yield 2;
}
let it = test()
console.log(it.next())
console.log(it.next())
console.log(it.next())
function* test() {
yield 1;
return 10;// 返回值
yield 2;
}
let it = test()
console.log(it.next())
console.log(it.next())
- 外部return,实例调用
function* test() {
yield 1;
yield 2;
}
let it = test()
console.log(it.next())
console.log(it.return(10))
console.log(it.next())
throw
- 必须要在第一次调用next之后调用throw,才能被捕获(捕获区间在try里的第一个yield之后)
- throw的表达式本身要是正确的
function* test() {
try {
yield 1;
yield 2;
} catch (e) {
console.log('生成器内部异常', e)
}
}
let it = test()
console.log(it.next())
console.log(it.throw(1))
console.log(it.next())
- 多次抛出只会捕获一个
function* test() {
try {
yield 1;
yield 2;
} catch (e) {
console.log('生成器内部异常', e)
}
}
let it = test()
console.log(it.next())
console.log(it.throw(1))
console.log(it.throw(2))
- throw的同时,也会往下走一步
function* test() {
try {
yield 1;
yield 2;
} catch (e) {
console.log('生成器内部异常', e)
}
yield 3;
}
let it = test()
console.log(it.next())
console.log(it.throw(1)) // 产出的是3不是2
- 捕获异步代码
const fs = require('fs')
const util = require('util')
const co = require('co')
let readFile = util.promisify(fs.readFile)
function* read() {
try {
let val1 = yield readFile('firsttxt', 'utf-8')
let val2 = yield readFile(val1, 'utf-8')
let val3 = yield readFile(val2, 'utf-8')
console.log('inner', val3)
} catch (e) {
console.log('异常捕获', e)
}
console.log('正常执行')
}
let it = read()
let promise = co(it)
promise.then((val) => {
console.log(val)
})
for…of循环
- 直接拿到值了,不是done/value了
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v); // 返回的是yield产出的值
}
// 1 2 3 4 5
实现斐波那契
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
遍历对象
const obj = {
a: 1,
b: 2,
c: 3
}
function* test(obj) {
for (let key in obj) {
yield [key, obj[key]]
}
}
for (let [key, val] of test(obj)) {
console.log(key + ':' + val)
}
const obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: test
}
function* test() {
for (let key in this) {
yield [key, this[key]]
}
}
for (let [key, val] of obj) {
console.log(key + ':' + val)
}
yield执行返回值
- 只能通过next的第二次调用拿到值
const fs = require('fs')
function promisifyAll(obj) {
for (let [key, fn] of Object.entries(obj)) {
if (typeof fn === 'function') {
obj[key + 'Async'] = promisify(fn)
}
}
}
promisifyAll(fs)
function promisify(func) {
return function (...args) {
return new Promise((resolve, reject) => {
func(...args, (err, data) => {
if (err) {
reject(new Error(err))
} else {
resolve(data)
}
})
})
}
}
let readFile = fs.readFileAsync
function* read() {
let val1 = yield readFile('first.txt', 'utf-8')
let val2 = yield readFile(val1, 'utf-8')
let val3 = yield readFile(val2, 'utf-8')
console.log('inner', val3)
}
let it = read()
let { value } = it.next()
value.then((val1) => {
let { value } = it.next(val1)
value.then((val2) => {
let { value } = it.next(val2)
value.then((val3) => {
console.log('val3', val3)
it.next(val3)
})
})
})
// val3 66
// inner 66
let it = read()
function Co(it) {
return new Promise((resolve, reject) => {
let next = (data) => {
let { value, done } = it.next(data)
if (done) {
resolve(value)
} else {
value.then((val) => {
next(val)
})
}
}
next()
})
}
let promise = Co(it)
promise.then((val) => {
console.log(val)
})
- 直接使用co包
// npm i co
let co = require('co')
let promise = co(it)
promise.then((val) => {
console.log(val)
})
yield*
- ES6 提供了yield*表达式,用来在一个 Generator 函数里面执行另一个 Generator 函数。
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
async await
- async替换*
- await替换yield
- async函数内无论写return什么,返回值都是promise(隐式通过Promise.resolve()包装了返回值)
const fs = require('fs')
const util = require('util')
const co = require('co')
let readFile = util.promisify(fs.readFile)
async function read() {
try {
let val1 = await readFile('first.txt', 'utf-8')
let val2 = await readFile(val1, 'utf-8')
let val3 = await readFile(val2, 'utf-8')
console.log('inner', val3)
} catch (e) {
console.log('异常捕获', e)
}
console.log('正常执行')
}
// let it = read()
// let promise = co(it)
// async await内置执行器 co
let promise = read()
promise.then((val) => {
console.log(val)
})
// 也可以在返回的promise.catch里捕获异常
- promise内部异常
const fs = require('fs')
const util = require('util')
const co = require('co')
let readFile = util.promisify(fs.readFile)
async function read() {
let val1 = await readFile('first.txt', 'utf-8')
console.log(a)
let val2 = await readFile(val1, 'utf-8')
let val3 = await readFile(val2, 'utf-8')
console.log('inner', val3)
console.log('正常执行')
}
let promise = read()
promise.then((val) => {
console.log(val)
}).catch((e) => {
console.log('catch到异常', e)
})
Promise.all
- 一个出错,在then里都拿不到,会在catch里捕获到第一个错误
const fs = require('fs')
const util = require('util')
let readFile = util.promisify(fs.readFile)
let f = Promise.all([
readFile('first.txt', 'utf-8'),
readFile('secondtxt', 'utf-8'),
readFile('thirdtxt', 'utf-8'),
])
f.then((val) => {
console.log('then', val)
}).catch((err) => {
console.log('err', err)
})