Async: `async`関数のサポート

作成日 2017年03月16日  ·  10コメント  ·  ソース: caolan/async

部屋の中の象の1つは、NodeとChromeに導入された新しいasync / awaitのサポートであり、まもなく他のすべての主要なブラウザーにヒットします。 私はAsyncがasync / awaitの世界で何ができるかを考えてきました。

現在、 asyncifyでラップすることにより、 async関数を適応させることができます。 async関数は基本的にPromiseを返す関数であるため、その古いアダプターはそれをコールバックスタイルの関数に簡単に変換できます。 しかし、それはややばかげた見た目になります:

async.mapLimit(arr, 10, async.asyncify(async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}), done);

ただし、 async関数の仕様の機能の1つは、次のとおりです。

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"

これにより、(ネイティブの) async関数を簡単に検出できます。 この手法を使用して、それらを自動的にasyncifyすることができます。 上記の例は次のようになります。

async.mapLimit(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}, done);

...これははるかに自然に流れるようです。 また、コールバックを引き続き使用する必要があると思います。 ユーザーが結果をawaitしたい場合は、関数をpromisifyにするか、全体としてpify非同期にする必要があります。

let result = await pify(async.mapLimit)(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
});

async関数を検出するための上記の方法は、ネイティブ関数でのみ機能します。 Babelのトランスパイルされた関数を検出する方法はないと思います。 コールバックをさかのぼって渡さないようにする必要があるため、Promisesを返すだけの通常の関数を確実に検出することはできません。 これは非常に近代的な環境ではトランスパイラーなしでのみ機能するという大きな警告があります。そうでない場合は、手動でasyncifyでラップする必要があります。

また、確かに、多くの非同期メソッドはasync / awaitでは意味がありません。 ほとんどの制御フローメソッド( autoqueueなどを除く)は、ネイティブの制御フロー構造を使用すると、より簡単に複製できます。 mapparallelは、 Promise.mapPromise.allに置き換えることができます。 ただし、コレクションの制限関数は、 autoやその他のいくつかの関数と同様に非常に便利です。 (また、$ async関数を使用したautoInjectは、非同期制御フローの夢です!)

enhancement feedback-wanted

最も参考になるコメント

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"を実行する理由はありますか、それともasyncFn[Symbol.toStringTag] === "AsyncFunction"を実行できますか(FFで機能するようです)?

これは、ECMA仕様の標準的な方法です。 理論的には、誰かがasyncFn[Symbol.toStringTag]を上書きする可能性があると思います。

したがって、誰かがcb(err、arg)形式のコールバックを提供するときはいつでも、それがAsyncFunctionであるかどうかを検出する必要があるという提案です。 非同期関数の場合はpromisifyを適用する必要があり、それ以外の場合はそのまま使用します

少し後ろ向きだと思います。 コールバックを受け入れるiteratee関数( function(args..., callback) {} )を受け入れる場合は常に、それがasync関数であるかどうかを確認してから、 asyncifyにする必要があります。

awaitの例は、Asyncメソッドをawaitしたい場合に、誰かが行うことです。 Asyncメソッドがpromiseを返し始めて、それが機能するようにするべきではないと思います。ユーザーに任せてください。

全てのコメント10件

これについてもう少し考えてみますが、これがどのように見えるかをよりよく想像できるように、いくつかの技術的な質問をしたいと思います。

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"を実行する理由はありますか、それともasyncFn[Symbol.toStringTag] === "AsyncFunction"を実行できますか(FFで機能するようです)?

誰かがcb(err, arg)の形式のコールバックを提供するときはいつでも、それがAsyncFunctionであるかどうかを検出する必要があるという提案です。 非同期関数の場合はpromisifyを適用する必要があり、それ以外の場合はそのまま使用します

また、申し訳ありませんが、awaitの例には従いません。関数がAsyncFunctionであることが検出された場合、 awaitをサポートする際の課題は何ですか?

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"を実行する理由はありますか、それともasyncFn[Symbol.toStringTag] === "AsyncFunction"を実行できますか(FFで機能するようです)?

これは、ECMA仕様の標準的な方法です。 理論的には、誰かがasyncFn[Symbol.toStringTag]を上書きする可能性があると思います。

したがって、誰かがcb(err、arg)形式のコールバックを提供するときはいつでも、それがAsyncFunctionであるかどうかを検出する必要があるという提案です。 非同期関数の場合はpromisifyを適用する必要があり、それ以外の場合はそのまま使用します

少し後ろ向きだと思います。 コールバックを受け入れるiteratee関数( function(args..., callback) {} )を受け入れる場合は常に、それがasync関数であるかどうかを確認してから、 asyncifyにする必要があります。

awaitの例は、Asyncメソッドをawaitしたい場合に、誰かが行うことです。 Asyncメソッドがpromiseを返し始めて、それが機能するようにするべきではないと思います。ユーザーに任せてください。

#1390で実装されました!

これは重大な変更であり、デプロイされたコードを破壊しました。 メジャーバージョンを増やさずにそういうことをするときはよく考えてください。

PS:このライブラリで行っているすべての素晴らしい作業に感謝します😄

シュート! 何が壊れたのか。 詳細を記載したチケットを作成していただけませんか
これが機能しなかった環境?
ありがとう!

2017年4月5日水曜日午前10時18分マニュエルヴァルスフェルナンデス<
[email protected]>は次のように書いています:

これは重大な変更であり、デプロイされたコードを破壊しました。 よく考えてください
メジャーバージョンを増やさずにそのようなことをするとき。

PS:このライブラリで行っているすべての素晴らしい作業に感謝します😄


コメントしたのでこれを受け取っています。
このメールに直接返信し、GitHubで表示してください
https://github.com/caolan/async/issues/1386#issuecomment-291875817 、またはミュート
スレッド
https://github.com/notifications/unsubscribe-auth/ADUIEPNkTSOVuuiwucBVrH983X6B568Wks5rs6K3gaJpZM4Mf64R

同意しました、それは私のビルドも壊しました...

数日前に機能していた非同期関数を呼び出していたウォーターフォールは、非同期コールバックが関数に提供されなくなったため、「cb isnotfunction」で失敗し始めました。

申し訳ありませんが、コードが壊れました。 async関数のユースケースは予想していませんでした。 コールバックを使用するのではなく、2.2.0にロールバックするか、コードを必要な値にリファクタリングすることをお勧めしreturn 。 残念ながら、猫はこの機能で袋から出されているので、ロールバックすることはできません。

@aearlyお願いします、言わないでください!! :1st_place_medalに答えてくれて本当にうれしいです:

@manvallsは、ロールバックする必要のない優れたソリューションを教えてくれました。 シンボルを使用して関数宣言のasyncを検出しているときに、彼は検出をだますための賢い方法を考えました。

私のウォーターフォールは他のモジュールからエクスポートされた関数を使用していましたが、そのうちの1つはasyncであり、失敗の原因でした。

したがって、次のように変更するだけです。

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: doThatAsync  
}; 

...
async.waterfall([
  services.doThis,
  services.doThat,  // fails with "cb is not a function"
], err => {
...
}

に:

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: (...args) => doThatAsync(..args)   // cheating the detection
}; 

...
async.waterfall([
  services.doThis,
  services.doThat, /* it works!!! */
], err => {
...
}

どうもありがとうございました

async.autoInject()でasync / awaitを使用できますか?

async.autoInject({

    conn1: async function () {
      return conn1;
    },

    conn2: async function () {
      return conn2;
    },
});

うまくいかないようです、私は得ます:

エラー:autoInjectタスク関数には明示的なパラメーターが必要です。
/Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async/dist/async.js:2081:23
/ Users / alexamil / WebstormProjects / nabisco / cdt-now / node_modules / asyncにあります

@ORESoftwareはい、 async関数はautoInjectで動作するはずです。 Chromeに投稿したコードをテストしたところ、実行されました。 conn1conn2undefined $であるため、最後のコールバックでReferenceErrorを受け取りました。 に変更した後

async.autoInject({
    conn1: async function () {
      return 'foo'
    },
    conn2: async function () {
      return 'bar'
    },
})

それはうまくいきます。 ただし、トランスパイルされasync関数はサポートされていません。 コードをトランスパイルしていますか?

このページは役に立ちましたか?
0 / 5 - 0 評価