从Redis返回数据仅仅是第二次

我正在使用Redis数据库并为api表示路由。 也使用node.js和ioredis。

我连接到Redis,然后获取所有与inputdate相关的密钥,然后获取与每个密钥相关的所有数据。

但是对我来说奇怪的是,这一切都是有效的,但只是在请求它的第二次刷新页面上。 所以在第一次加载页面(比如blah.com/api/20120120)时,它将返回一个空的数组。 然后,如果刷新页面,它将返回正确的数据。

HomeController.js:

var theData = []; function getData (date) { redis.on('ready', function (res) { var keys = []; var stream = redis.scanStream( { match: date + '*', count: 1000 } ); stream.on('data', function (resultKeys) { for (var i = 0; i < resultKeys.length; i++) { keys.push(resultKeys[i]); } }); stream.on('end', function () { setValues(keys); }); }); return theData; } var setValues = function(keys) { for (var i = 0; i < keys.length; i++) { redis.hgetall(keys[i], function (err, result) { theData.push(result); }) } } var HomeController = Controller.extend({ api: function (date) { this.setRender(); this.getResponse().json(getData(date)); } }); 

Server.js:

 app.get("/api/:date", router("HomeController", "api", ["date"])); 

任何人有任何想法为什么发生这种情况?

编辑:添加controller.js:

 (function(module) { "use strict"; // https://github.com/darlanalves/extends var extend = require("extends"); var Class = function() {}; var Controller = extend(Class, { constructor: function(req, resp) { this._request = req; this._response = resp; this._view = null; this._viewProperties = {}; this._render = true; this.assign("loggedIn", false); this.assign("location", req.protocol + '://' + req.get('host') + req.originalUrl); }, assign: function(key, value) { this._viewProperties[key] = value; return this; }, assignObject: function(obj) { for (var key in obj) { if (obj.hasOwnProperty(key)) { this.assign(key, obj[key]); } } }, failWith404: function() { this.getRequest().log({status:404}, "controller 404"); this.getResponse().status(404).render('404.jade'); }, getRequest: function() { return this._request; }, getResponse: function() { return this._response; }, getView: function() { return this._view; }, getViewProperties: function() { return this._viewProperties; }, render: function() { var viewProps = this.getViewProperties(), logProps = { loggedIn: viewProps.loggedIn, }; if (this._render !== true) { // No rendering, no headers } else if (this.getView() !== null) { // Jade this.getResponse().render(this.getView(), this.getViewProperties()); } else { // JSON response this.getResponse().json(this.getViewProperties()); } this.getRequest().log(logProps, "controller hit"); }, setRender: function(renderEnabled) { this._render = (renderEnabled === true); }, setView: function(viewName) { this._view = viewName; } }); module.exports = Controller; })(module); 

你有一个问题,这是asynchronous。

我也怀疑,在每个后续的请求,你会得到你在前一个请求的数据。 另外如果你有多个用户,他们可能会得到别人的请求。

关键问题:您的theData超出了getData函数的范围。 另一个关键问题 – 你同步解决这个问题。

简化你的代码:

 var theData = []; function getData (date) { redis.on('ready', handler); return theData; } 

那么,先调用algorithm:

  1. 将数据设置为[]
  2. 设置一些handler来等待redis ready事件。
  3. 返回theData (即[]);
  4. 稍后(当redis准备就绪时),你的处理程序将theData设置为结果。

第二个电话:

  1. 您不要设置数据 – 仅在您的模块第一次加载。 这意味着,数据是你最后设置的(这是前一个请求的数据,由handler设置)。
  2. 再次安排handler来做一些事情。
  3. 返回theData (现在保存上一次调用的数据)。
  4. 处理程序稍后将数据设置为新数据。

等等

基本上是asynchronous问题。

编辑:您的示例代码更新后:

所以随着你的代码更新,你必须做这样的事情:

getData函数应该是asynchronous的(返回一个Promise或使用callback)。 和你的HomeController。

例:

 let HomeController = Controller.extend({ api: function (date) { this.setRender(); getData(date) // Get data asynchroonously here .then(function(data) { this.getResponse().json(data); }) .catch(function(err) { // handle error this.getResponse().status(500).json({message: 'Error getting data'); }); } }); 

但现在有一个问题 – getData需要返回一个Promise。

 let Promise = require('bluebird'); //unless you have Node 0.12+, it has Promise already. function getData(date) { return new Promise(function(resolve, reject) { let theData = []; // initialize empty data for each req redis.on('ready', function() { var keys = []; var stream = redis.scanStream({ match: date + '*', count: 1000 }); stream.on('data', function (resultKeys) { for (var i = 0; i < resultKeys.length; i++) { keys.push(resultKeys[i]); } }); stream.on('end', function () { resolve(setValues(keys)); // Here we `resolve` our promise }); stream.on('error', reject); // just a minor thing } }); } 

但是现在你的setValues也需要是asynchronous的,再次用Promise:

 function setValues(keys) { // Return a promise to the initial caller. return new Promise(function(resolve, reject) { let parallelizedQueries = keys.map(function(key) { // Now, EACH of the hgetall also needs to be a Promise or somehow async return new Promise(function(innerResolve, innerReject) { redis.hgetall(key, function(err, result) { if (err) { return innerReject(err); } innerResolve(result); }); }); }); // So now we have asked for each of the keys, in parallel. // Wait until all of them succeed or fail on the first one. Promise.all(parallelizedQueries) .then(function(data) { // Here is our data. return resolve(data); }) .catch(reject); }); } 

这应该让你开始,希望你能从这里工作。