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 不允许请求标头字段

如何将DynamoDB放入请求放入队列

使用 SQL Server 后端将图片插入到 Access 表中

如何使用 Ruby 作为后端将 React 上的图像上传到 Google Cloud Storage

python后端将svc文件数据读入数据库具体实现