最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Generator和async/await

    正文概述 掘金(fatG)   2020-12-04   535

    前言

    纯属个人学习过程中的笔记,方便后续的复习,如果有错误或者更好的方法,希望看到的大佬不吝赐教

    Generator

    学习Generator之前,需要简单了解一下迭代器

    迭代器

    有next方法,执行返回结果对象,返回的对象有done和value两个属性
    下面用代码看一下迭代器是个什么东西

            function createIterator(list) {
                let i = 0;
                return {
                    next() {
                        let done = i >= list.length;
                        let value = !done ? list[i++] : undefined;
                        return {
                            done,
                            value,
                        };
                    },
                };
            }
            let iterator = createIterator([1, 2, 3]);
            console.log(iterator.next()); //{ done: false, value: 1 }
            console.log(iterator.next()); //{ done: false, value: 2 }
            console.log(iterator.next()); //{ done: false, value: 3 }
            console.log(iterator.next()); //{ done: true, value: undefined }
    

    Generator(生成器)

    • ES6异步编程解决方案
    • 通过function* 声明
    • 返回符合可迭代协议和迭代协议的生成器对象
    • 在执行时能暂停,又能从暂停处继续执行

    yield

    • 只能出现在Generator函数中
    • 用来暂停和恢复生成器函数

    next

    • 遇到yeild暂停,将紧跟yeild表达式的值作为返回对象的value
    • 没有yeild,执行到return ,将return的值作为返回对象的value
    • 没有return 返回对象的value是undefined
    • next可以携带一个参数,可以作为上一个yeild(暂停的那个)表达式的返回值
            function* generator() {
                let first = yield 1;
                let second = yield first + 2;
                let thrid = yield second + 3;
                return 1;
            }
            let g = generator();
            console.log(g.next()); // {value: 1, done: false}
            console.log(g.next(2)); // {value: 4, done: false}
            console.log(g.next(3)); // {value: 6, done: false}
            console.log(g.next()); // {value: 1, done: true} //如果没有return ,value则是undefined
    

    yeild*

    • 是生成器函数/可迭代对象
    • 可以委托其他生成器
    • 用来复用生成器

    通俗的说,就是yeild* 可以在生成器中调用另外一个生成器,还是看代码

            function* generator1() {
                yield 1;
            }
    
            function* generator2() {
                yield 100;
                yield* generator1();
                yield 200;
            }
            let g2 = generator2();
            console.log(g2.next()); //{value:100,done:false}
            console.log(g2.next()); //{value:1,done:false}
            console.log(g2.next()); //{value:200,done:false}
            console.log(g2.next()); //{value:undefined,done:true}
    

    return

    • return,可以带一个参数,结束生成器的执行,返回对象的value为传的参数,不传则为undefined
            function* generator() {
                yield 100;
                yield 200;
            }
            let g = generator();
            console.log(g.next()); //{value:100,done:false}
            console.log(g.return(123)); //{value:1,done:true}
            console.log(g.next()); //{value:undefined,done:true }
    

    throw

    • 可以让生成器内部抛出错误
            function* generator() {
                let first = yield 1;
                let second;
                try {
                    second = yield first + 2;
                } catch (error) {
                    second = 6;
                }
                yield second + 3;
            }
            let g = generator();
            console.log(g.next()); //{value:1,done:false}
            console.log(g.next(1)); //{value:3,done:false}
            //可以看出由于有trycatch,抛出的错误被捕获到,所以走到了catch里面,second为6
            console.log(g.throw(new Error("error"))); //{value: 9, done: false}
            console.log(g.next()); //{value:undefined,done:true}
    

    协程

    Generator是怎么实现的呢,需要了解一下协程
    协程:可以暂停执行(暂停的表达式称之为暂停点),也可以从挂点恢复执行(保留其原始参数和局部变量)
    一个线程存在多个协程,但是只能同时执行一个协程
    Generator就是协程在ES6上面的表现
    yield就是挂起协程,next则是唤醒协程

    Generator函数的应用

    用setTimeout 模拟异步 //这种方法虽然不会造成回调地狱,但是代码耦合度比较高

            function* generator() {
                function test(num) {
                    setTimeout(() => {
                        console.log(num);
                        g.next(num);
                    }, 2000);
                }
                let r1 = yield test(1);
                console.log(r1, "r1");
                let r2 = yield test(2);
                console.log(r2, "r2");
            }
            let g = generator();
            g.next();
    

    thunk

    为了解决上述代码的耦合问题,需要使用thunk函数,可以自动执行Generator函数
    函数比较绕,先上完整代码,然后慢慢理解

    const fs = require("fs");
    
    function thunk(fn) {
        return function(...args) {
            return function(callback) {
                return fn.call(this, ...args, callback);
            };
        };
    }
    let readFileThunk = thunk(fs.readFile);
    
    function* generator() {
        let r1 = yield readFileThunk("./test1.json");
        console.log(r1, "r1");
        let r2 = yield readFileThunk("./test2.json");
        console.log(r2, "r2");
        let r3 = yield readFileThunk("./test3.json");
        console.log(r3, "r3");
    }
    
    function run(fn) {
        let gen = fn();
    
        function go(data, err) {
            console.log(data, err, "data123");
            let result = gen.next(data);
            if (result.done) return;
            result.value(go);
        }
        go();
    }
    run(generator);
    

    readFileThunk

    function(...args) {
            return function(callback) {
                return fs.readFile.call(this, ...args, callback);
            };
        };
    

    result.value

    function(callback) {
                return fs.readFile.call(this, ...args, callback);
            };
    

    run的参数是生成器,运行之后拿到迭代器gen,然后执行next方法,如果返回的对象的value是false,则将go作为result.value的参数,result,value执行的时候,意味着fs.readFile执行,传入的callback(go)将作为fs.readFile的参数(回调函数)执行,然后又再一次回到了go函数内部,反之返回对象的value是true 的时候,则结束执行

    async/await

    async/await是Generator和promise的语法糖

    async

    • 返回值:返回一个promise对象,return的值是promise resolved时候的value,Throw的值是promise rejected时候的reason
    
          async function test1() {
            return 1;
          }
          let p1 = test1(); //一个promise
          p1.then((res) => {
            console.log(res); //1
          }); 
    
          async function test2() {
            throw new Error("error");
          }
          let p2 = test2();
          p2.catch((err) => {
            console.log(err); //Error: error
          });
    
    

    await

    • 只能出现在async函数内部或者最外层
    • 等待一个promise对象
    • await的promise对象状态为rejected的时候,后续执行中断
    • 如果希望执行,可以在后面加一个catch或者在trycatch中执行
          async function test() {
            console.log(1);
            await Promise.resolve().then(() => {
              console.log(2);
            });
            console.log(3);
          }
          test(); // 1 2 3
    
          async function test() {
            console.log(1);
            await Promise.reject();
            console.log(3);
          }
          test(); // 1
          async function test() {
            console.log(1);
            await Promise.reject().catch((err) => {
              console.log(2);
            });
            console.log(3);
          }
          test(); // 1 2 3
          async function test() {
            console.log(1);
            try {
              await Promise.reject();
            } catch (error) {
              console.log(2);
            }
            console.log(3);
          }
          test(); // 1 2 3
    

    async函数使用

            async function test() {
                console.log(1);
                await new Promise((resolve, reject) => {
                    setTimeout(() => {
                        console.log(2);
                        resolve();
                    }, 3000);
                });
                console.log(3);
                await new Promise((resolve, reject) => {
                    setTimeout(() => {
                        console.log(4);
                        resolve();
                    }, 2000);
                });
            }
            test(); //1 2 3 4
    

    起源地下载网 » Generator和async/await

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元