在NodeJS中使用promises,我加载了一个模型,然后可以通过对NodeJS应用程序的后续调用来重用它。如果第二个请求在第一个请求仍然被加载时到达,我如何防止从数据库加载两次相同的对象/模型?
我设置了一个"加载标志"说正在从数据库中检索对象并且"已加载"完成后。如果有第二个请求尝试加载同一个对象,则需要等到初始模型被填充,然后两者都可以使用相同的对象。
示例代码(简化,ES6,节点0.10 [旧有原因])。
需要解决的是TODO。
应用:
import ClickController from './controllers/ClickController'
import express from 'express'
const app = express()
app.get('/click/*', (req, res) => {
// Get the parameters here
let gameRef = "test";
ClickController.getGameModel(gameRef)
.then(() => {
console.log('Got game model')
return this.handleRequest()
}, (err) => {
throw err
})
}
控制器:
import gameModel from '../models/GameModel'
class ClickController {
constructor(config) {
// Stores the objects so they can be re-used multiple times.
this.loadedGames = {}
}
// getGameModel() as a promise; return model (or throw error if it doesn't exist)
getGameModel(gameRef) {
return new Promise((resolve, reject) => {
let oGame = false
if(typeof this.loadedGames[gameRef] === 'undefined') {
oGame = new gameModel()
this.loadedGames[gameRef] = oGame
} else {
oGame = this.loadedGames[gameRef]
}
oGame.load(gameRef)
.then(function() {
resolve()
}, (err) => {
reject(err)
})
})
}
}
模型/对象:
class GameModel {
constructor {
this.loading = false
this.loaded = false
}
load(gameRef) {
return new Promise((resolve, reject) => {
if (this.loading) {
// TODO: Need to wait until loaded, then resolve or reject
} else if (!this.loaded) {
this.loading = true
this.getActiveDBConnection()
.then(() => {
return this.loadGame(gameRef)
}, (err) => {
console.log(err)
reject(err)
})
.then(() => {
this.loading = false
this.loaded = true
resolve()
})
} else {
// Already loaded, we're fine
resolve()
}
})
}
// As this uses promises, another event could jump in and call "load" while this is working
loadGame(gameRef) {
return new Promise((resolve, reject) => {
let sql = `SELECT ... FROM games WHERE gameRef = ${mysql.escape(gameRef)}`
this.dbConnection.query(sql, (err, results) => {
if (err) {
reject('Error querying db for game by ref')
} else if (results.length > 0) {
// handle results
resolve()
} else {
reject('Game Not Found')
}
})
})
}
}
答案 0 :(得分:3)
我并不完全遵循您要求的代码中的哪一部分,而是在请求已经在飞行中#34时缓存带有承诺的值的常用方案;是这样的:
var cachePromise;
function loadStuff(...) {
if (cachePromise) {
return cachePromise;
} else {
// cache this promise so any other requests while this one is stil
// in flight will use the same promise
cachePromise = new Promise(function(resolve, reject) {
doSomeAsyncOperation(function(err, result) {
// clear cached promise so subsequent requests
// will do a new request, now that this one is done
cachePromise = null;
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
return cachePromise;
}
}
// all these will use the same result that is in progress
loadStuff(...).then(function(result) {
// do something with result
});
loadStuff(...).then(function(result) {
// do something with result
});
loadStuff(...).then(function(result) {
// do something with result
});
这保留了缓存的承诺,只要请求是"在飞行中",cachePromise
值就位,并且将由后续请求返回。
请求一旦完成,cachePromise
将被清除,以便稍后发出的下一个请求将发出新请求。