js非同期入門から放棄(四)-Generatorパッケージ非同期タスク


前の記事では、従来の非同期の実現方法を紹介していますが、ここではES 6の新たな非同期スキームであるGenerator関数を紹介します.
generator概要
簡単にgeneratorの原理と文法を紹介します.
基本文法
簡単な例で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
    上のアクチュエータは既に原形を持っていますが、前の例では、reult.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関数の流れを制御し、適切なタイミングでプログラムの実行権を受信し、返却します.しかし、具体的な実現方法は唯一ではありません.例えば、本稿では最も簡単で直接的なコールバック関数方式を使って、阮一峰先生の『es 6入門』教程で、thunkの考え方を使って説明する部分もあります.自分で調べられます.