【问题标题】:ExpressJS backend put requests into a queueExpressJS 后端将请求放入队列
【发布时间】:2023-04-04 09:47:01
【问题描述】:

我有客户端发送要由服务器执行的任务,但这些请求应该像队列一样处理。知道我该怎么做吗?谢谢。

    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) {
        //....
      })

    })

【问题讨论】:

标签: node.js express promise bluebird


【解决方案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>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-05-19
          • 2018-08-12
          • 1970-01-01
          • 1970-01-01
          • 2012-03-31
          • 2021-01-13
          • 1970-01-01
          • 2017-02-13
          相关资源
          最近更新 更多