從co到koa01-co

thunk

  • 他的發展是由函數的求值策略的分歧決定的,兩種求值策略
    • 傳值調用,在進入函數體以前就直接執行完,把值傳進去
    • 傳名調用,將表達式傳入函數體,只在用到他的時候求值
  • 傳名函數的編譯器實現,其實就是放入一個臨時函數,再將臨時函數傳入函數體,這個臨時函數就叫作thunk函數
  • js語言是傳值調用,他的thunk含義有些不一樣,js中,thunk函數替換的不是表達式,而是多參數函數,將它替換成單參數的版本,且只接受回調函數做爲參數
  • 任何有回調的函數都是能夠搞成thunk形式的,下面是一個簡單的生成器
var Thunk = function(fn){
    return function () {
      //先傳入其餘的參數初始化
      var args = Array.prototype.slice.call(arguments);
      //傳入callback返回的函數
      return function(callback){
        args.push(callback);
        //實際調用的時候
        return fn.apply(this,args);
      }
    }
  }
  var readFileThunk = Thunk(fs.readFile);
  readFileThunk(fileA)(callback);

generator

  • Generator是爲JavaScript設計的一種輕量級的協程。它經過yield關鍵字,能夠控制一個函數暫停或者繼續執行generator函數
function * hello (name) {
    yield 'your name is: ' + name
    return 'input name is: ' + name
}

const gen = hello('jinks')

//your name is: jinks
gen.next().value
//input name is: jinks
gen.next().value

CO

  • co的根本目的:將異步操做跟在yield後面,當異步操做完成並返回結果後,再觸發下一次next() 。跟在yield後面的異步操做須要遵循必定的規範thunks和 promises
//簡化版co
const fs = require('fs')
const Q = require('Q')
const readdir = Q.denodeify(fs.readdir)

//或者thunk規範
const thunkify = require('thunkify')
const readdir = thunkify(fs.readdir)

function co(generator) {
    return function (fn) {
        fn = fn || function () {}

        const gen = generator()
       
        function next (err, result) {
            if(err) {
                return fn(err)
            }
            
            const step = gen.next(result)
            
            if(!step.done) {
                // thunk
                step.value(next)
                // promise
                step.value.then(res => next(null, res)).catch(err => next(err))
            } else {
                fn(null, step.value)
            }
        }
        next()
    }
}

function *test() {
    const result = yield readdir(dir)
}

co(test)((err, result) => {
    console.log(err, result)
})
相關文章
相關標籤/搜索