跳转至

Generator函数与协程原理及实现

进程与线程的概念就不一一叙述了

协程

协程是一种基于线程之上,但是又比线程更加轻量级的存在,这种由程序员自己写程序来管理的轻量级线程叫做【用户空间线程】,具有对内核来说不可见的特性

正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程

协程的Generator函数实现

Generator函数就是异步任务的一个容器

通过yield关键字指定异步任务

function* gen(x) {
    var y = yield x + 2 // 阶段一,用yield来划分阶段
    return y // 阶段二
}
var g = gen(1)
g.next() // {value:3,done:false},调用一次next执行一个阶段,done表示函数内部还有没有执行完成的阶段
g.next() // {value:undefined,done:true}

function* gen(x) {
    var y = yield x + 2 // 阶段一,x+2  用yield来划分阶段
    return y // 阶段二 var y ={上一个阶段返回的结果},return y
}
var g = gen(1)
g.next() // {value:3,done:false},调用一次next执行一个阶段,done表示函数内部还有没有执行完成的阶段
g.next(2) // {value:3,done:true},将上一个阶段返回的结果2给下一个阶段即,var y =2,return y


function* gen(x) {
    try{
         var y = yield x + 2 
    }catch(e){
        console.log(e)
    }
    return y 
}
var g = gen(1)
g.next()
g.throw('出错了') // 用于抛错

异步任务封装

还需要详细了解Generator函数~~

var fetch = require('node-fetch')

function* gen(){
    var url ='https://...'
    var result = yield fetch(url) // 阶段一:var url ='https://...';fetch(url)
    console.log(result) // 阶段二:var result = {},console.log(result)
}

var g = gen()
var result = g.next()
result.value.then(function(data){
    retuen data.json();
}).then((data)=>{
    g.next(data)
})

基于Thunk函数封装Generator自动执行器

传值调用和传名调用

对于如下函数

var x=1
function f(m){
    return m*2
}
f(x+5)

传值调用

func(x+5)
等同于
func(6)

传名调用

func(x+5)
等同于
(x+5)*2

传值调用和传名调用,各有各的好处,取决于入参在函数内部是否被使用以及使用的频率

thunk函数的含义

var x=1
function f(m){
    return m*2
}
f(x+5)
// 等同于
var thunk = function(){
    return x+5
}
function f(thunk){
    return thunk()*2
}

定义一个自动执行器

var fetch = require('node-fetch')

function* gen(){
    var url ='https://...'
    var result = yield fetch(url) // 阶段一:var url ='https://...';fetch(url)
    console.log(result) // 阶段二:var result = {},console.log(result)
}
function run(gen) { // gen是一个Generator函数,优点类似于前端常用的对axios的封装
    var g = gen();
    function next(data) {
        var result = g.next()
        if(result.done) return result.value
        result.value.then(function(data){
            return data.json()
        }).then(function(data){
            next(data)
        })
    }
    next()
}
//将Generator函数作为入参传进去即可
run(gen)