当前位置: 首页 > 科技观察

你是否对JS中的Generator及协程真正理解-

时间:2023-03-13 00:29:08 科技观察

JS中的Generator和Coroutine你真的了解吗?转载本文请联系前端三元同学公众号。生成器是ES6中的新语法。和之前的异步语法相比,还是比较难上手。所以这里我们先来熟悉一下Generator的语法。生成器执行过程什么是生成器函数?生成器是一个带星号的“函数”(注意:它不是真正的函数),可以通过yield关键字暂停和恢复。例如:function*gen(){console.log("enter");leta=yield1;letb=yield(function(){return2})();return3;}varg=gen()//阻塞,不会执行任何语句控制台。log(typeofg)//对象看到了吗?不是“函数”console.log(g.next())console.log(g.next())console.log(g.next())console.log(g.next())//enter//{value:1,done:false}//{value:2,done:false}//{value:3,done:true}//{value:undefined,done:true}从这里我们可以看出生成器那里执行中有几个关键点:调用gen()后,程序会阻塞,不会执行任何语句。调用g.next()后,程序继续执行,直到遇到yield程序暂停。next方法返回一个具有两个属性的对象:value和done。value为当前yield后的结果,done表示执行是否完成。遇到return后done会由false变为true。yield*语法当一个生成器调用另一个生成器时,使用yield*会派上用场。比如下面这个例子:function*gen1(){yield1;yield4;}function*gen2(){yield2;yield3;}我们要按照1234的顺序执行,怎么办呢?在gen1中,修改如下:function*gen1(){yield1;yield*gen2();yield4;}修改完之后依次调用next。生成器实现机制——协程大家可能比较好奇,生成器是如何挂起功能的,又会如何恢复呢?接下来,让我们仔细看看执行机制——协程。什么是协程?协程是比线程更轻量级的存在。协程处于线程环境中。一个线程可以有多个协程。协程可以理解为线程中的一个任务。与进程和线程不同,协程不受操作系统管理,而是由特定的应用程序代码控制。协程的运行过程那么你可能要问了,JS不是单线程执行的吗,这么多协程可以一起执行吗?答案是不。一个线程一次只能执行一个协程。比如当前正在执行A协程,还有一个B协程。如果要执行B的任务,就必须在A协程中将JS线程的控制权交给B协程。现在B执行了,A完全处于挂起状态。举个具体的例子:function*A(){console.log("我是A");yieldB();//A停止,将线程执行权转移给Bconsole.log("结束了");}functionB(){console.log("我是B");return100;//返回,将线程执行权还给A}letgen=A();gen.next();gen.next();//我是A//我是B//结束在这个过程中,A把执行权交给了B,也就是A启动了B,我们也称A为B的父协程。因此,最后的return100inB实际上将100传递给父协程。需要强调的是,对于协程来说,它不受操作系统的控制,完全是用户自定义的切换,所以没有进程/线程上下文切换的开销,这是高性能的重要原因。