ExpressJS 后端将请求放入队列
Posted
技术标签:
【中文标题】ExpressJS 后端将请求放入队列【英文标题】:ExpressJS backend put requests into a queue 【发布时间】:2016-07-05 03:12:05 【问题描述】:我有客户端发送要由服务器执行的任务,但这些请求应该像队列一样处理。知道我该怎么做吗?谢谢。
express.Router().post('/tasks', function(req, res)
//This is the task to perform. While being performed, another user
//might send a request AND should only be processed when this is done.
//This should also flag the pending task if it is completed.
Promise.resolve(req.body)
.then(function()
//..
)
.catch(function(error)
//....
)
)
【问题讨论】:
看看here 【参考方案1】:当然,这很简单,假设你有一个函数 fn
会返回一个承诺。
var res = fn(req.body); // returns the appropriate promise
并且您想在其中添加排队。您必须执行以下操作:
用fnQueued
装饰fn
,这样当fnQueued
被调用时,我们:
为价值创建一个新的承诺。
排队工作
幸运的是,这几乎是 promise 对 then
所做的事情,因此我们可以重用它而不是实现我们自己的排队逻辑:
function queue(fn)
var queue = Promise.resolve(); // create a queue
// now return the decorated function
return function(...args)
queue = queue.then(() => // queue the function, assign to queue
return fn(...args); // return the function and wait for it
);
return queue; // return the currently queued promise - for our argumnets
这会让我们做类似的事情:
var queuedFn = queue(fn);
express.Router().post('/tasks', function(req, res)
queuedFn(req.body).then(v => res.json(v), e => res.error(e));
);
【讨论】:
【参考方案2】:@BenjaminGruenbaum 的回答非常棒,但并不完全清楚。这是额外的清晰度和有效的 sn-p(布丁的证明):
const queue = (fn) =>
let q = Promise.resolve()
return (...args) =>
q = q.then(() => fn(...args)).catch(() =>
// noop
)
return q
const speak = (sayWhat, delay) =>
return new Promise((resolve) =>
setTimeout(() =>
console.log('say', sayWhat)
resolve()
, delay)
)
const speakQueued = queue(speak)
const helloBtn = document.getElementById('hello-btn')
const byeBtn = document.getElementById('bye-btn')
helloBtn.onclick = () => speakQueued('hello there', 1000)
byeBtn.onclick = () => speakQueued('bye bye', 2000)
<button id="hello-btn">say hello (1 sec wait)</button>
<button id="bye-btn">say bye (2 sec wait)</button>
【讨论】:
【参考方案3】:这里更多的是一种面向对象的方法来解决这个问题。这提供了更多控制,例如,仅对以前未见过的项目进行排队。
class QueueUnique
items = []
q
func
constructor(func)
this.q = Promise.resolve()
this.func = func
add(item)
const done = this.items.find(itm => itm.id === item.id)
if (done)
console.log(`not adding item $item.id because it has already been queued`)
else
const queuedFunc = this.queue(item)
queuedFunc()
this.items.push(item)
queue(item)
return () =>
this.q = this.q.then(() => this.func(item)).catch(() =>
// noop
)
return this.q
const speak = (item) =>
return new Promise((resolve) =>
setTimeout(() =>
console.log('say', item.sayWhat)
resolve()
, item.delay)
)
const queue = new QueueUnique(speak)
const btn1Click = () =>
queue.add(id: 1, sayWhat: 'one', delay: 1000)
const btn2Click = () =>
queue.add(id: 2, sayWhat: 'two', delay: 2000)
const btn3Click = () =>
queue.add(id: 3, sayWhat: 'three', delay: 3000)
const btn4Click = () =>
queue.add(id: 4, sayWhat: 'four', delay: 4000)
const btn5Click = () =>
queue.add(id: 5, sayWhat: 'five', delay: 5000)
<button onclick="btn1Click()">button 1</button>
<button onclick="btn2Click()">button 2</button>
<button onclick="btn3Click()">button 3</button>
<button onclick="btn4Click()">button 4</button>
<button onclick="btn5Click()">button 5</button>
【讨论】:
【参考方案4】:这是另一个面向对象的解决方案和另一个工作示例,它允许您查看排队的项目。此解决方案不使用承诺链(但仍需要func
来返回承诺)。
const elItems = document.getElementById('items')
const elSuccess = document.getElementById('success')
const elFailure = document.getElementById('failure')
class QueueUnique
items = []
success = []
failure = []
processing = false
func
constructor(func)
this.func = func
add(item)
const allItems = [...this.items, ...this.success, ...this.failure]
const addItem = !allItems.some(itm => itm.id === item.id)
if (!addItem)
console.log(`QueueUnique not adding item $item.id because it has already been queued`)
else
this.items = [...this.items, item]
console.log(`QueueUnique adding item $item.id to queue position $this.items.length`)
this.process()
process()
this.update() // this method is not needed and just updates the arrays shown on screen
if (!this.processing && this.items.length)
this.processing = true
const item = this.items[0]
console.log(`QueueUnique start executing item $item.id`)
this.func(item).then(() =>
console.log(`QueueUnique success executing item $item.id`)
this.complete(true)
).catch(err =>
console.log(`QueueUnique failure executing item $item.id - $err.message`)
this.complete(false)
)
complete(success)
const item = this.items[0]
this.items = this.items.filter(itm => itm.id !== item.id)
if (success)
this.success = [...this.success, item]
else
this.failure = [...this.failure, item]
this.processing = false
this.process()
update()
elItems.innerhtml = this.items.map(item => item.id)
elSuccess.innerHTML = this.success.map(item => item.id)
elFailure.innerHTML = this.failure.map(item => item.id)
const speak = (item) =>
return new Promise((resolve) =>
setTimeout(() =>
console.log('say', item.sayWhat)
resolve()
, item.delay)
)
const queue = new QueueUnique(speak)
const btn1Click = () =>
queue.add(id: 1, sayWhat: 'one', delay: 1000)
const btn2Click = () =>
queue.add(id: 2, sayWhat: 'two', delay: 2000)
const btn3Click = () =>
queue.add(id: 3, sayWhat: 'three', delay: 3000)
const btn4Click = () =>
queue.add(id: 4, sayWhat: 'four', delay: 4000)
const btn5Click = () =>
queue.add(id: 5, sayWhat: 'five', delay: 5000)
div
display: inline-block;
margin: 5px 0 0 10px;
padding: 2px 5px;
border-radius: 3px;
background-color: #DDD;
<button onclick="btn1Click()">button 1</button>
<button onclick="btn2Click()">button 2</button>
<button onclick="btn3Click()">button 3</button>
<button onclick="btn4Click()">button 4</button>
<button onclick="btn5Click()">button 5</button>
<div>items <span id="items"></span></div>
<div>success <span id="success"></span></div>
<div>failure <span id="failure"></span></div>
【讨论】:
以上是关于ExpressJS 后端将请求放入队列的主要内容,如果未能解决你的问题,请参考以下文章
NodeJS + ExpressJS:预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段
使用 SQL Server 后端将图片插入到 Access 表中