如何保存NodeJS应用程序,直到其他承诺完成

时间:2015-12-14 03:35:36

标签: node.js es6-promise

在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')
                }
            })

        })
    }
}

1 个答案:

答案 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将被清除,以便稍后发出的下一个请求将发出新请求。