如何使请求同步等待同一 NodeJS/express 网络服务的另一个请求?
How to make a request sync wait for another request of the same NodeJS/express webservice?
我已经简化了我的代码,我正在寻找一种方法来正确等待内部 var 增加(如互斥锁)。
请求 #1:/call
首先从浏览器调用,必须等待,请求 #2:/trigger
例如从另一个浏览器调用,然后请求 #1 必须 return它的结果。
这是我的示例代码,很简单,但是"TODO"部分很难。我已经尝试过使用 while 循环,但它阻止了整个过程并且不接受请求 #2(我认为它可以用 promises 或 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
});
});
可以使用事件实现:
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
)
可能最容易使用 publish/subscribe 模式,例如:
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
});
});
当然,使用像 RxJs 这样的库比我在几分钟内拼凑的一些随机代码更受欢迎。
顺便说一句,考虑改用 websockets。
我已经简化了我的代码,我正在寻找一种方法来正确等待内部 var 增加(如互斥锁)。
请求 #1:/call
首先从浏览器调用,必须等待,请求 #2:/trigger
例如从另一个浏览器调用,然后请求 #1 必须 return它的结果。
这是我的示例代码,很简单,但是"TODO"部分很难。我已经尝试过使用 while 循环,但它阻止了整个过程并且不接受请求 #2(我认为它可以用 promises 或 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
});
});
可以使用事件实现:
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
)
可能最容易使用 publish/subscribe 模式,例如:
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
});
});
当然,使用像 RxJs 这样的库比我在几分钟内拼凑的一些随机代码更受欢迎。
顺便说一句,考虑改用 websockets。