ここに:
Post.find({}, function(err, docs) {
if (docs.length == 0)
return res.send({ message: "No posts" });
docs.length == 0
の条件に達した場合 、次にリクエストへの応答を送信します。ただし、return
Post.find()
からのみ返されます 折り返し電話。 trendingposts()
から戻ってこない 機能。
その間、その関数は実行を継続し、最終的に次のコードに到達します。
var mysort = { score: -1 };
Post.find({})
.populate("postedBy")
.populate("comments.postedBy")
.populate("comments.incomments.postedBy")
.populate("comments.likes")
.sort(mysort)
.limit(10)
.exec((er, result) => {
res.json(result);
});
次に、同じリクエストに対して別の応答を送信します。これがエラーのトリガーになりますCannot set headers after they are sent to the client
これを防ぐにはさまざまな方法がありますが、それらはすべて、この関数を一般的にクリーンアップする方法に関連している可能性があります。現在の記述方法では、基本的に2つの完全に別個の非同期コードパスを開始します。どちらもPost.find({})
で始まります そこから行きます。それらはそれぞれ並列で実行され、他のコードパスが何をしているのかまったくわかりません。そのため、一方から応答を送信する具体的な方法はありませんが、両方を送信することはできません。
したがって、これをクリーンアップする方法は、2つの完全に別個の非同期コードパスを持たないことです。何らかの方法でそれらを調整する必要があります。ここでのほとんどすべての場合、データベースへのpromise-interfaceに切り替える必要があります。これにより、制御フローを管理するためのより多くのオプションが提供されます。たとえば、パフォーマンス上の理由から、promiseを使用して2つの並列非同期操作を同時に実行する場合は、Promise.all()
を使用できます。 またはPromise.allSettled()
両方を監視し、いつ完了したかを確認してから、両方の結果を手元に置いて、送信する応答を決定します。
または、シーケンスを作成する場合は、async/await
を使用できます。 2つの操作をかなり簡単に順序付けてから、return
を実行すると、 、実際には最上位の機能から戻り、それ以上の制御フローを停止します。
データベースへのコールバックインターフェイスを使い続けたい場合は、res.send({ message: "No posts" })
。