簡單理解Generator自執行及async、await語法原理

爲了更加方便的處理異步操做問題,
如今最新的前端框架生態都開始用上了Generator和yield,
有的甚至已經開始使用最新的async、await語法了,
這兩樣都是基於Generator自動執行的原理。javascript


這裏就簡單理解下Generator自執行及async、await語法原理:前端

1、thunk函數

thunk函數指的是能將執行結果傳入回調函數,並將該回調函數返回的函數。
是否是有點抽象,舉個例子:java

var readFile = function (fileName) {
    return function (callback) {
        return fs.readFile(fileName, callback)
    }
}

下面咱們來看下thunk函數怎樣執行es6

readFile('./package.json')((err, str) => {
    console.log(str.toString())
})

問: thunk的執行比普通函數要麻煩很多,那麼它有什麼優點呢?json

thunk函數的優點在於它能將異步操做返回結果的獲取權交給thunk函數的返回值,
而不是將異步操做結果傳入thunk函數自己的做用域內,這點很重要,
由於它能結合Generator語法讓Generator函數自動執行前端框架

2、Generator

es6的Generator函數,具體語法這裏就不介紹了,框架

咱們來編寫一個基於thunk函數的Generator:異步

let gen = function* () {
    let r1 = yield readFile('./package.json')
    console.log(r1.toString())
    let r2 = yield readFile('./index.js')
    console.log(r2.toString())
}

咱們來手動執行一下這個Generator:async

let g = gen()
let r1 = g.next()
r1.value(function (err, data) {
    if (err) {
        throw err
    }
    let r2 = g.next(data)
    r2.value(function (err, data) {
        if (err) {
            throw err
        }
        g.next(data)
    })
})

能夠注意到,在咱們手動執行基於thunk函數的Generator時,
有不少代碼是能夠複用的,
沒錯,所謂的Generator自動執行就是把這些可複用的部分封裝成函數,
而後讓它們遞歸執行,直到執行完全部的yield。函數

3、Generator自動執行器

下面就是Generator自動執行的核心代碼

function run(fn) {
    let gen = fn()
    function next(err, data) {
        let result = gen.next(data)
        if (result.done) {
            return
        }
        result.value(next)
    }
    next()
}

能夠看到無非就是把可複用的部分封裝成next函數,而後讓其遞歸執行,
直到執行完全部的yield

其調用代碼爲:

run(gen)

這樣就將本來繁雜的異步操做封裝的十分簡單了

基於Promise的Generator的自動執行

上面的例子是基於thunk函數的,而即將出現的es7的async、await語法是基於Promise的

這裏再上一個基於Promise的Generator的自動執行

//包裝返回Promise對象的函數
function readFile(fileName) {
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, (error, data) => {
            if (error) {
                reject(error)
            } else {
                resolve(data)
            }
        })
    })
}

// 編寫Generator
let gen = function* () {
    let r1 = yield readFile('./package.json')
    console.log(r1.toString())
    let r2 = yield readFile('./index.js')
    console.log(r2.toString())
}

// 編寫Generator執行器
function run(gen) {
    let g = gen()
    function next(data) {
        let result = g.next(data)
        if (result.done) {
            return result.value
        }
        result.value.then((data) => next(data))
    }
    next()
}

//用Generator執行器自動執行
run(gen)

這個和基於thunk函數的大同小異,只是把函數返回值的獲取權以Promise的方式交出

但願這篇文章能幫助你簡單的理解Generator自執行及async、await語法原理 ^.^

相關文章
相關標籤/搜索