Используя промисы с NodeJS, я загружаю модель, которую затем можно повторно использовать при последующих вызовах приложения NodeJS. Как я могу предотвратить двойную загрузку одного и того же объекта/модели из базы данных, если второй запрос поступает, пока первый все еще загружается?
Я установил «флаг загрузки», чтобы сказать, что объект извлекается из базы данных и «загружается» по завершении. Если есть второй запрос, который пытается загрузить тот же объект, ему нужно дождаться заполнения исходной модели, после чего оба могут использовать один и тот же объект.
Пример кода (упрощенный, ES6, Node 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')
}
})
})
}
}