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

How to hold a NodeJS application until other promise completes

使用 NodeJS 的承诺,我加载了一个模型,随后可以通过对 NodeJS 应用程序的调用重新使用该模型。如果第二个请求到达而第一个请求仍在加载,我如何防止从数据库中加载相同的 object/model 两次?

我设置 "loading flag" 表示正在从数据库中检索对象,完成后 "loaded"。如果有第二个请求试图加载同一个对象,则需要等到初始模型被填充,然后两者才能使用同一个对象。

示例代码(简化版,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')
                }
            })

        })
    }
}

我不完全理解你问的是代码的哪一部分,但是在请求已经 "in-flight" 时用承诺缓存值的通常方案是这样工作的:

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
});

这保持了缓存的承诺,只要请求是 "in-flight",cachePromise 值就位并且将由后续请求返回。

一旦请求实际完成,cachePromise 将被清除,以便稍后出现的下一个请求将发出新请求。