現在の動作は非常に驚くべきものです。
await async.parallel({foo: async()=>Promise.all([1,2])})
// { foo: [ 1, 2 ] }
await async.parallel({foo: ()=>Promise.all([1,2])})
// waits forever because non-async function expects a ballback
短い関数の場合、 foo: () => doSomething()
書くだけで魅力的です。 そこでasync
キーワードを忘れるのはとても簡単です
しかし、現在これは機能しません。 foo: async () => doSomething()
と書く必要があります
関数がAsyncFunctionであるかどうかをチェックする代わりに、コールバックが渡されたかどうかをチェックできますか?
関数がpromiseを返すかどうか、および関数にコールバックを渡す必要があるかどうかを事前に確実に検出する方法はありません。 ( Function.length
またはFunction.toString()
解析では不十分です)これがasyncify
目的です-promiseを返す関数をコールバックを受け取る関数に変換します。 async
関数はタイプが異なるため検出できるため、自動的にasyncify
できます(これが内部でどのように機能するかを示しています)。 しかし、たまたまpromiseを返す通常の関数の場合、Asyncがそれらを呼び出す前にそれを知る方法はありません。
@aearlyうーん、
async function parallel(o, cb) {
if (!cb) { // promise behavior
return Object.fromEntries(
await Promise.all(Object.entries(o).map(async ([k, v]) => [k, await v()]))
)
}
// else do the callback behavior
}
私たちはすでにそのようなものです- async.parallel
へのコールバックを省略した場合はpromiseを返します。 コールバックを省略した場合でも、ユーザーの意図を想定する方法がないため、渡された関数がpromiseを返すとは想定していません。 多分私はあなたが何を意味するのか誤解していますか?
わかりました、具体的にしましょう: https ://repl.it/@caub/async -async
// npm.im/async expects all inner functions to be async,
// even when using no outer callback (as 2nd arg of async.parallel)
console.log(
await async.parallel({
foo: async () => delay(1000).then(() => 1),
bar: async (rs) => {
return 2
},
})
);
// Doesn't work without those async,
// but I'd like this to resolve just like above instead of freezing
console.log(
await async.parallel({
foo: () => delay(1000).then(() => 1),
bar: () => {
return 2
},
})
);
将来の次のメジャーバージョンでは、次のような方法でのみコールバックをサポートすることが興味深いと思います。
await Promise.all([
{ then(resolve){ setTimeout(resolve, 50, 1) } }, // callback way
2,
delay(45).then(())=>3)
])
// [1, 2, 3]
内部関数で不要なasync
キーワードの必要性を排除します
利点は、より明確です。 ユーザーの意図を想定しないことについてのあなたのポイントは理解していますが、Promiseの解決を使用したいときに人々がasync
キーワードを忘れないだろうとあなたはまだ想定しています
これにより、下位互換性がかなり大きく損なわれます。たとえば、 Async.map(fileNames, fs.readFile)
ようなことはもうできません。
どこで壊れるか説明してもらえますか?
現在壊れているのは:
await async.map(['server.js', 'package.json'], fs.readFile) // works
await async.map(['server.js', 'package.json'], fs.promises.readFile) // works
await async.map(['server.js', 'package.json'], s => fs.promises.readFile(s)) // doesn't work
await async.map(['server.js', 'package.json'], async s => fs.promises.readFile(s)) // works
アイデアは3番目のものを修正することです
私はそれらの問題を絶えず受けます、例えば私は書いた:
// ...
doc = await async.map(items, item => item.toDoc(currentUser, options));
async item => item.toDoc..
が見つからなかったため、どこかでタイムアウトしました
その場合、私が一人なら価値はありませんが、もっと多くの人がこの状況にあるのであれば、提案された変更を検討する価値があると思います
async.map
を使用したこの例も非常に代表的なものです。これは、私のポイントをどのように見ることができるかを示しています。
doc = await Promise.all(items.map(item => item.toDoc(currentUser, options)));
async item => item.toDoc..
必要とせずに動作します
3番目のものを確実に修正する方法はありません。これは過去に多くの議論がありました。 関数の戻り値を確認してから、遡及的に関数にコールバックを渡さないようにすることはできません。 async
キーワードは
@caub恥知らずなプラグインはここにありますが、 asyncp
は、ここで探しているものを処理する機能があると思います。
この問題が解決されたとしても、上記のリンクされた問題の時点で、ここで@caubステートメントを再度強調したいと思います。
現在の動作は私を大いに混乱させました。私は(一種の)ここで説明した技術的な制限を理解していますが、ドキュメントは単に現在の動作と一致していないと思います。
たとえば、mapLimitの場合、「リターン:コールバックが渡されない場合は、promise」と表示されます-コールバックバージョンから始めて、基本的にコールバックを省略し、Promiseが取得されないことに驚きました( 'async'キーワード)。
また、iteratee関数の「callback」ステートメントは必要ありません。代わりに、値を「返す」必要があります。
したがって、混乱を避けるために、動作を変更する(推奨)か、少なくともドキュメントと例を私の観点で調整する必要があります。
@caubこれが理由です
https://github.com/caolan/async/blob/8aecf108b3922bc5211036706a0f6f75e02bd42b/lib/internal/wrapAsync.js#L3:L5
function isAsync(fn) {
return fn[Symbol.toStringTag] === 'AsyncFunction';
}
このように、関数が実際に呼び出さなくてもpromiseが返されるかどうかを確認する方が簡単です。 ただし、これはasync / awaitの規則に反することに同意してください。 内部await
なしでasync
キーワードを追加することは、ほとんどの場合、実際には悪い習慣と見なされます。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_functionから
async
関数の本体は、0個以上のawait式で分割されていると考えることができます。 最初のawait式(存在する場合)までの最上位コードは、同期的に実行されます。
...したがって、コードがbabelによってトランスパイルされた場合、たとえばasync
キーワードが存在するという理由だけでコードとステップが追加されるため、パフォーマンスのオーバーヘッドがいくらか追加されます。
たとえば、次のようになります。
async function foo() { return 1 }
...と同等です:
function foo() { return Promise.resolve(1) }
しかし、このライブラリでは、
async.mapLimit([1], 1, async v => v)
と
async.mapLimit([1], 1, v => Promise.resolve(v)))
同等ではありません!
最も参考になるコメント
この問題が解決されたとしても、上記のリンクされた問題の時点で、ここで@caubステートメントを再度強調したいと思います。
現在の動作は私を大いに混乱させました。私は(一種の)ここで説明した技術的な制限を理解していますが、ドキュメントは単に現在の動作と一致していないと思います。
たとえば、mapLimitの場合、「リターン:コールバックが渡されない場合は、promise」と表示されます-コールバックバージョンから始めて、基本的にコールバックを省略し、Promiseが取得されないことに驚きました( 'async'キーワード)。
また、iteratee関数の「callback」ステートメントは必要ありません。代わりに、値を「返す」必要があります。
したがって、混乱を避けるために、動作を変更する(推奨)か、少なくともドキュメントと例を私の観点で調整する必要があります。