js异步从入门到放弃(四)- Generator 封装异步任务

栏目: JavaScript · 发布时间: 5年前

内容简介:在之前的文章介绍了传统异步的实现方案,本文将介绍ES6中的一种全新的异步方案--Generator函数。简单介绍一下generator的原理和语法,(更详细内容请看通过一个简单的例子来了解

在之前的文章介绍了传统异步的实现方案,本文将介绍ES6中的一种全新的异步方案--Generator函数。

generator简介

简单介绍一下generator的原理和语法,(更详细内容请看 ECMAScript 6 入门 ,本文只介绍和异步相关的核心内容)

基本语法

通过一个简单的例子来了解 generator 函数

function* MyGenerator() {
    yield 'yield的含义是:执行此处时,暂停执行当前函数'
    yield '暂停之后的函数可以用next方法继续执行'
    return '遇到return之后会真正结束,done会变成true'
}

const gen = MyGenerator() //执行后返回的是一个指针,可以利用该指针执行next方法
console.log(gen.next()) // {value: "yield的含义是:执行此处时,暂停执行当前函数“, done: false}
console.log(gen.next())// {value: "暂停之后的函数可以用next方法继续执行", done: false}
console.log(gen.next())// {value: "遇到return之后会真正结束,done会变成true", done: true}

数据交互

数据交互指的是 可以通过yield把当前执行的结果传出,也可以使用next把外部参数传入

function* MyGenerator(){
        const result = yield '传出的数据'
        return result
    }
    const gen = MyGenerator()
    console.log(gen.next())// generatorAndAsync2.html:19 {value: "传出的数据", done: false}
    console.log(gen.next('传入的数据'))// {value: "传入的数据", done: true}

交互的参数类型当然也可以是 函数

function sayHi(){
        console.log('hi');
    }
    
    function* MyGenerator(){
        const result = yield sayHi()
        return 
    }
    
    const gen = MyGenerator()
    const result = gen.next()// {value: sayHi, done: false}
    result.value() // 正常输出'hi'

具备以上最核心的两个特性之后,generator就可以进行异步操作封装。

异步任务封装

首先,结合异步任务的特点以及前文提到的genrator函数的特性,提炼出使用generator封装异步操作的核心思路:

yield
next

起步

从一个最简单的例子开始:

// 1. 首先写一个异步任务,在一秒后返回特定字符串
function asyncTask(callback){
    setTimeout(()=>{
        callback('Hello Leo')
    }, 1000)
}

// 2. 接下来写出期望执行的顺序
function* runTask() {
    let text = yield asyncTask
    console.log(text) // 我们期望这里正常输出Hello Leo
}
// 3. 按照期望值执行函数
const gen = runTask()// 此时执行权已经交出
gen.next().value(function (text) {// 执行asyncTask并传入callback ,关键点在于在callback里调用next交还执行权
    gen.next(text)
})

首先,这段代码虽然很粗糙,但是已经反映了使用 generator 封装异步任务的核心思想。最直观的受益就是: runTask 的内容看起来很像同步代码,条理清晰,很适合阅读。

但是上面第3部分关于执行的代码很不灵活,我们不能每次都这么写一段,因此接下来的目标就是 实现一个任务执行器

自动任务执行器

同样的,先思考核心的思路:要想让某个 generator 函数自动执行,无非就是一个 while 循环:

1. 如果当前yield返回值的done属性为true,说明任务已经执行完成;
2. 如果当前yield返回值的done属性为false,说明任务还未执行完成,则继续执行next,同时要注意参数传递

根据分析实现以下的执行器:

function autoExecute(task) {
    const gen = task()
    let result = gen.next()
    while(true){
        if(result.done){
            break // 执行结束
            return 
        }
        console.log(result.value)//为了便于观察 我们加上console.log
        result = gen.next(result.value) // 每次都应该重写result 获取最新结果
    }
}

function* simpleTask(){
    yield 1
    yield 2
    yield 3
    return 
}

autoExecute(simpleTask)// 测试我们写的自动执行器 能够正确输出123

上面的执行器已经有了雏形,但是对于前面例子中, result.value为函数的情况 还没有处理,因此还需要稍微补充:

function isFunction(source){
     return Object.prototype.toString.call(source) === "[object Function]"
}

function autoExecute(task) {
    const gen = task()
    let result = gen.next()
    let isRuningAsync = false // 由于加入了异步处理,所以要增加一个标志位避免重复进入循环体
    while (!isRuningAsync) {
        if (result.done) {
            return
        }
        console.log(result.value)

        /* start 补充的处理函数 */
        if (isFunction(result.value)) {
            isRuningAsync = true
            const callback = (arg) => {
                result = gen.next(arg) // 核心代码
                isRuningAsync = false
            }
            result.value(callback)
            /* end 补充的处理函数 */
        } else {
            result = gen.next(result.value)
        }
    }
}
autoExecute(runTask) // 试着用这个自动执行器执行之前的异步任务

上面这个自动执行器,就完成了generator对异步任务的封装。

总结

本文简要介绍了generator函数的一些特性,重点在于说明如何使用 generator 函数对异步任务进行封装,从而能够让异步代码编写的更加清晰。

再次强调:用 generator 函数对异步任务封装的思想是很明确的-- 控制 Generator 函数的流程,在适当的时机接收和交还程序的执行权,但是具体的实现方式并不唯一,例如本文用的是最简单直接的回调函数方式,在阮一峰老师的《es6入门》教程里,也有使用thunk思路来讲解的部分,可以自行查阅。


以上所述就是小编给大家介绍的《js异步从入门到放弃(四)- Generator 封装异步任务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Filter Bubble

The Filter Bubble

Eli Pariser / Penguin Press / 2011-5-12 / GBP 16.45

In December 2009, Google began customizing its search results for each user. Instead of giving you the most broadly popular result, Google now tries to predict what you are most likely to click on. Ac......一起来看看 《The Filter Bubble》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具