Node.js 多个请求同时返回一个结果

Node.js multiple requests at same time and one result returning

多个用户可以同时调用请求,所以我想做的是,如果一个用户调用请求并且正在开始计算结果,那么当另一个用户调用相同的请求时结果计算没有开始,但是等待对于第一个用户要求的结果。换句话说,只有当另一个用户不是 'locked' 时才应该开始计算结果,如果是 - 然后等待结果。

已编辑

代码:

结果:

像这样?

/** @type {[express.Request, express.Response][]} */
let requestQueue = [];

/**
 * @param {express.Request} req 
 * @param {express.Response} res 
 */
async function processRequest( req, res ) {
    var result = await GetResults();
    res.end(result);
    if (requestQueue.length !== 0) processRequest.apply(requestQueue.shift());
}

app.get("/getresults", (req, res) => {
    if (requestQueue.length !== 0) return requestQueue.push([req, res]);
    processRequest(req, res);
});

编辑: 如果他们都收到相同的结果,则此代码:

/** @type {Promise} */
let requestPromise = null;

app.get("/getresults", (req, res) => {
    if (requestPromise === null) requestPromise = GetResults().finally(() => requestPromise = null); // returns a promise
    res.send(await requestPromise);
});

为了保证并发请求的结果不会被多次计算,你需要实现某种锁定机制(如你所料)。

这是您的代码的一个非常基本的示例,如果互斥量当前已锁定,它只是将请求推送到队列。如果不是,则计算结果,并且对于所有待处理的请求,将发送具有计算值的响应:

const express = require('express');
const app = express();

class Mutex {
    constructor() {
        this.queue = [];
        this.locked = false;
    }

    lock() {
        return new Promise((resolve, reject) => {
            if (this.locked) {
                this.queue.push([resolve, reject]);
            } else {
                this.locked = true;
                resolve();
            }
        });
    }

    release(value) {
        if (this.queue.length > 0) {
            const [resolve, reject] = this.queue.shift();
            resolve(value);
        } else {
            this.locked = false;
        }
    }
}

const getResultsMutex = new Mutex();

function getResults() {
    return new Promise((resolve => {
        setTimeout(() => resolve(Math.random()), 5000);
    }))
}

function sendResponse(result, req, res) {
    res.send("The result is " + result);
}

app.get('/getresults', async (req, res) => {
    let result = await getResultsMutex.lock();
    if (!result) {
        result = await getResults();
    }
    sendResponse(result, req, res);
    getResultsMutex.release(result);
});

app.listen(4000, function () {
    console.log("Server is running at port 4000");
});