2017-04-21 18 views
0

次は、制御フローラッパーcoを実装して、非同期コードをyieldキーワードでのみ記述できるようにします。JavaScriptでのコルーチン制御フローの実装

これは基本的に何ですか?async/awaitは何ですか?

co(function*() { 
 
    console.log('...'); 
 
    yield one(); 
 
    console.log('...'); 
 
    yield two(); 
 
}) 
 

 

 
function co(gFn) { 
 
    var g = gFn(); 
 

 
    return Promise.resolve() 
 
     .then(go); 
 

 
    function go() {   
 
     var result = g.next(); 
 
     if(result.done) { 
 
      return; 
 
     } 
 
     if(isPromise(result.value)) { 
 
      return result.value.then(go); // Promises block until resolution. 
 
     } 
 
     return Promise.resolve(result); 
 
    }  
 
} 
 

 
function isPromise(o) { 
 
    return o instanceof Promise; 
 
} 
 

 
function one() { 
 
    return new Promise(resolve => setTimeout(() => (console.log('one'), resolve()), 1000)); 
 
} 
 

 
function two() { 
 
    return new Promise(resolve => setTimeout(() => (console.log('two'), resolve()), 1000)); 
 
}

編集:私は検討の戻り値に取るように更新された応答の光で

co(function*() { 
 
    console.log('...'); 
 
    const result1 = yield one(); 
 
    console.log('result1: ', result1); 
 
    const result2 = yield two(); 
 
    console.log('result2: ', result2); 
 
    const result3 = yield[one(), two()]; 
 
    console.log('result3: ', result3); 
 
    const result4 = yield{ 
 
     one: one(), 
 
     two: two() 
 
    }; 
 
    console.log('result4: ', result4); 
 
}) 
 

 
function co(gFn) { 
 
    var g = gFn(); 
 

 
    return Promise.resolve().then(go); 
 

 
    function go() { 
 
     var result = g.next(...arguments); 
 
     if (isPromise(result.value)) { 
 
      return result.value.then(go); 
 
     } 
 
     if (Array.isArray(result.value)) { 
 
      return Promise.all(result.value).then(go); 
 
     } 
 
     if (isObject(result.value)) { 
 
      var o = {}; 
 
      var promises = Object.keys(result.value).map(k=>result.value[k].then(r=>o[k] = r)); 
 
      return Promise.all(promises).then(()=>o).then(go); 
 
     } 
 
     return Promise.resolve(result); 
 
    } 
 
} 
 

 
function isPromise(o) { 
 
    return o instanceof Promise; 
 
} 
 

 
function isObject(val) { 
 
    return val && (Object === val.constructor); 
 
} 
 

 
function one() { 
 
    return new Promise(resolve=>setTimeout(()=>(console.log('one'), 
 
    resolve('result 1')), 1000)); 
 
} 
 

 
function two() { 
 
    return new Promise(resolve=>setTimeout(()=>(console.log('two'), 
 
    resolve('result 2')), 1000)); 
 
}

+0

は、「これは、 '非同期/ await'は、ボンネットの下に何をするか、基本的ですESの中には何か? " - 一つのアプローチと他のアプローチとの同等性を判断するための調査のみですか? – guest271314

+1

どのような蒸散器のカバーの下で見たことがありますか? –

+0

@PhilCooper私は 'co'ソースを見てきました。 – Ben

答えて

3

これは基本的にasync/awaitが何のESで何をしているのですか?

実際はありません。同じことをするための別のアプローチです。何に変身async/awaitすると、より

async function foo() { 
    const bar = await Bar(); 
    bar++; 
    const baz = await Baz(bar); 
    return baz; 
} 

よう

function foo() { 
    return Bar() 
    .then(bar => { 
     bar++; 
     return Baz(bar) 
     .then(baz => { 
      return baz; 
     }); 
    }); 
} 
+0

@Bergiしかし、編集で追加したコード( '.then(baz => {return baz;})')はノーオペレーションです。 –

+1

これも 'const baz = ...;です。 return as baz; ':-) [追加の解決策は別として、実際には役に立たない](http://stackoverflow.com/a/41089205/1048572)、' async'/'await'の翻訳は機械的で、あなたのコードに役に立たない 'await'を置いたので、よく... – Bergi

+0

@torazaburo、ちょっと、ちょっと変わった例が約束のアプローチにどのように翻訳されているかを含めるようにあなたの答えを広げてください。これは変更された例です: 'const bar = await Bar(); someAsyncFn();バー++; ... '。 promise chainに影響を与えずに 'bar ++;'と一緒に実行されますか? –

3

Stage 3 Draft/January 26, 2016 Async Functionsは、3つのパターンの例を提供するとなっています。 Promise; Generator; Async Functions;異なるアプローチは、本質的に

Examples#

同じ結果を生成する場所最初の約束を用いて書かれた、以下の例を取ります。このコード は、アニメーションに 例外があるときに停止し、最終的に正常に実行されたアニメーションで最後に生成された値を返します。

function chainAnimationsPromise(elem, animations) { 
    let ret = null; 
    let p = currentPromise; 
    for(const anim of animations) { 
     p = p.then(function(val) { 
      ret = val; 
      return anim(elem); 
     }) 
    } 
    return p.catch(function(e) { 
     /* ignore and keep going */ 
    }).then(function() { 
     return ret; 
    }); 
} 

すでに約束して、コードがはるかにループして例外処理のこの種のは、挑戦的な あるストレートコールバックスタイルから改善されています。

function chainAnimationsGenerator(elem, animations) { 
    return spawn(function*() { 
     let ret = null; 
     try { 
      for(const anim of animations) { 
       ret = yield anim(elem); 
      } 
     } catch(e) { /* ignore and keep going */ } 
     return ret; 
    }); 
} 

これは顕著な改善である:

Task.jsと同様のライブラリが同じ意味を維持するコードを単純化 を促進するために発電機を使用する方法を提供します。コードのセマンティックコンテンツを上回る、そしてそれを超えた定型文のすべてが削除され、内部関数の本体がユーザーの意図を表します。しかし、追加の ジェネレータ関数にコードをラップし、それをライブラリに渡して約束事に変換する定型文の外層は です。 このレイヤーは、この メカニズムを使用して約束を生成するすべての関数で繰り返す必要があります。これは典型的な非同期 Javascriptコードでは非常に一般的であり、 残存定型句の必要性を排除することに価値があることがわかります。 、残りのすべての定型文が削除され、非同期機能付き

、 は、プログラムテキストでのみ意味的に意味のあるコードを残して:_

async function chainAnimationsAsync(elem, animations) { 
    let ret = null; 
    try { 
     for(const anim of animations) { 
      ret = await anim(elem); 
     } 
    } catch(e) { /* ignore and keep going */ } 
    return ret; 
}