这段代码是否尊重NodeJS的异步处理方式?它完全正常工作,但我不明白为什么res.render
在Database.findOne
回调中,而不在Database.aggregate
回调中,即使我是{m}使用Database.findOne
和Database.aggregate
的结果。
但是,如果我将res.render
放在Database.aggregate
和Database.findOne
之外,但仍在router.get
回调中,则代码无法正常工作在所有(编辑:当然,在这种情况下,我声明数据库查询之外的变量)。怎么会? NodeJS的正确做法是什么?
由于
var _ = require('lodash');
var express = require('express');
var Database = require('../models/database');
var router = express.Router();
router.get('/:XXXX', function(req, res, next) {
var XXXX = req.params.XXXX;
var aggregationResults;
Database.aggregate([
// pipeline
], function(err, results) {
aggregationResults = results;
if (err) return next(err);
});
Database.findOne({XXXX: XXXX}, function(err, XXXXresult){
if(err) return next(err);
res.render('page', {XXXXresult: XXXXresult, aggregationObject : aggregationResults[0]});
});
});
答案 0 :(得分:2)
在您的代码中,您调用两个异步数据库函数并将回调传递给每个函数。在这里,您首先调用Database.aggregate()
并传递回调,该回调将结果存储在变量即aggregationResults
中。然后你正在调用Database.findOne()
并将回调传递给它,它会发送两个调用的结果。
这是有效的,因为您的第一个数据库调用(Database.aggregate()
)在第二个数据库调用之前解析(即Database.findOne()
)。因此,在您的第二个数据库回调中,您假设第一个数据库调用的结果可用。
但总有可能并非如此。例如,第一个数据库可能会失败,第二个数据库可能会通过。在这种情况下,没有第一个数据库的结果。
NodeJS的正确做法是什么?
早些时候它曾经是一个嵌套的回调,但今天你应该使用promise。您的代码将看起来像这样:
Database.aggregate([pipeline]).then(function(results) {
aggregationResults = results;
return Database.findOne({XXXX: XXXX});
}).then(function(XXXXresult){
res.render('page', {XXXXresult: XXXXresult, aggregationObject : aggregationResults[0]});
});
您可以使用bluebird之类的库来宣传您的数据库方法。
答案 1 :(得分:1)
如果您将res.render
移到findOne
回调之外,它将在回调之前执行 - 您将无法获得任何数据。毕竟,在路由器(req, res, next)
回调之后,这些数据库操作将完成。
在您当前的代码中,假设aggregate
和findOne
函数是异步的,您就会遇到竞争条件。如果findOne
回调在aggregate
回调之前执行,那么TypeError
将会aggregationResults
未定义findOne
。
解决此问题的最简单方法是将aggregate
调用放入Promise.all
回调中。但这实际上并不是一个好主意,因为这两个函数将一个接一个地执行,这比同时执行它们要慢。
你应该做的是使用Promises,并使用import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
public class ItemTwoFragment extends Fragment {
public Player player;
public static ItemTwoFragment newInstance(){
ItemTwoFragment fragment=new ItemTwoFragment();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
View view=inflater.inflate(R.layout.fragment2,container,false);
player=new Player(view);
return view;
}
}
class Player extends YouTubeBaseActivity{
YouTubePlayerView player;
YouTubePlayer.OnInitializedListener onInitializedListener;
public Player(View view) {
player=(YouTubePlayerView) view.findViewById(R.id.player);
onInitializedListener=new YouTubePlayer.OnInitializedListener() {
@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
youTubePlayer.loadPlaylist("ANak509iCl4&list=PLj9JLcynHDZ6Ymoz8GEWy0U9RDtRM4P_2");
}
@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
}
};
player.initialize("AIzaSyCYuQjVhqjVA_I2tPMa-Egy4x-d7KFVFDQ",onInitializedListener);
}
}
和2个promises之类的东西在两个操作完成后发送响应。