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 = 0let map = new Map()for (let [key, value] of Object.entries(this)) {map.set(key, value)}let mapEntries = [...map.entries()],len = mapEntries.lengthreturn {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都是undefinedyield 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)
})