Как заставить синхронизацию запроса ждать другого запроса того же NodeJS / экспресс-веб-сервиса? - PullRequest
0 голосов
/ 21 января 2019

Я упростил свой код и ищу метод для правильного ожидания увеличения внутренней переменной (например, мьютекса).

Запрос № 1: /call сначала вызывается из браузераи должен ждать, запрос # 2: /trigger вызывается, например, из другого браузера, а затем запрос # 1 должен вернуть свой результат.

Вот мой пример кода, довольно простой, но часть "TODO"очень сложно.Я уже пробовал с циклом while, но он блокирует весь процесс и не принимает запрос №2 (я думаю, что это можно сделать с помощью обещаний или с помощью async / await, но я не вижу, как их использовать)

[code was removed, cf. below]

Спасибо за продвижение!

РЕДАКТИРОВАТЬ: Большое спасибо вам, grappeq !Вот мой рабочий код в соответствии с шаблоном публикации и подписки, который обновлен, поэтому /trigger и /call можно запускать в любом порядке:

var app = require('express')();
var token = 0;
require("http").createServer(app).listen(8080, () => {
    console.log("Launched");
});
class Quartz {
    constructor() {
        this.callbacks = [];
    }
    retry() {
        throw "";
    }
    call(callback) {
        this.callbacks.push(callback);
        this.trigger();
    }
    trigger(...args) {
        var failedCallbacks = [];
        while (this.callbacks.length > 0) {
            var callback = this.callbacks.shift();
            try {
                callback(...args);
            } catch (e) {
                failedCallbacks.push(callback);
            }
        }
        this.callbacks = failedCallbacks;
    }
};
var quartz = new Quartz();
app.get('/call', (request, response) => {
    console.log("Wait");
    var start = Date.now();
    quartz.call(() => {
        if (token <= 0)
            quartz.retry();
        token--;
        response.status(200).json({
            "func": "/call",
            "value": token,
            "time": Date.now()-start
        });
    });
});
app.get('/trigger', (request, response) => {
    console.log("Trigger");
    var start = Date.now();
    token++;
    quartz.trigger();
    response.status(200).json({
        "func": "/trigger",
        "value": token,
        "time": Date.now()-start
    });
});

Ответы [ 2 ]

0 голосов
/ 21 января 2019

Вероятно, проще всего использовать шаблон публикации / подписки , например:

var app = require('express')();
var token = 0;
require("http").createServer(app).listen(8080, () => {
    console.log("Launched");
});

class PubSub {
    constructor() {
        this.callbacks = [];
    }

    sub(callback) {
        this.callbacks.push(callback);
    }

    pub(...args) {
        this.callbacks.forEach(callback => { callback(...args); });
    }
};

var pubsub = new PubSub();

app.get('/call', (request, response) => {
    console.log("Call");
    var start = Date.now();
    pubsub.sub(() => {
        response.status(200).json({
            "func": "/call",
            "value": token,
            "time": Date.now()-start
        });
    })
});
app.get('/trigger', (request, response) => {
    console.log("Trigger");
    var start = Date.now();
    pubsub.pub();
    response.status(200).json({
        "func": "/trigger",
        "value": token,
        "time": Date.now()-start
    });
});

Конечно, использование такой библиотеки, как RxJ, должно быть предпочтительнее, чем случайный код, который я собрал в несколькоминут.

Кстати, рассмотрите использование вместо веб-сокетов .

0 голосов
/ 21 января 2019

Может быть достигнуто с помощью События:

var events = require('events');
var eventEmitter = new events.EventEmitter();

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

app.listen(8080, () => {
    console.log("Launched");
});

app.get('/call', (req, res) => {
    console.log("Call");

    var start = Date.now();

    eventEmitter.on('tokenEvent', (token) => {
        res.status(200).json({
            "func": "/call",
            "value": token,
            "time": Date.now() - start
        });
    });

});


app.get("/trigger", (req, res) => {
    console.log("Trigger");
    var start = Date.now();

    var token = 1;

    eventEmitter.emit('tokenEvent', token);

    res.status(200).json({
        "func": "/trigger",
        "value": token,
        "time": Date.now() - start
    });

});

Обратите внимание, что вам, вероятно, понадобится защитить линии:

eventEmitter.on('tokenEvent', (token) => {
        res.status(200).json({

, потому что /trigger можно вызвать до /call (!res.headersSent можно использовать)

...