【co】ES6-20/21 iterator与generator

在这里插入图片描述

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)
})

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值