保存JavaScript承诺以供将来使用

时间:2017-07-11 14:19:33

标签: javascript node.js promise

我正在使用Node.js来构建服务器端RESTApi。当我自己测试时,Node工作正常。但是当它真的存在时它仍然可能面临溢出问题。当有很多请求时,假设有5个以上的child_process(spawn)同时工作,每个进程都需要更长的时间,基本上会减慢一切。

我的想法是检查当前进程是否低于某个限制(例如,一次限制为3个进程),如果超出限制,我将请求保存到数组中,并且每当当前进程低于限制,我使用.shift()弹出数组中最旧的一个并处理它。

然而,当涉及到Promises时,由于我不知道我们是否可以将Promise存储到阵列中,或者我是否应该让这个过程停顿几秒钟而变得困难。我认为这是一个好主意。

如果您希望将来承诺并将承诺退还给客户,那么正常的方法是什么?

对不起,如果我没有说明这一点。以下是我的疑惑摘要: 我们能否保留未来使用的承诺? 我们把它们保存在阵列中吗? 3.我应该使用其他方法来保持承诺,例如,使用sleep()或只是一个while循环来等待这个过程继续进行?

谢谢!

2 个答案:

答案 0 :(得分:2)

  

说有超过5个child_process(spawn)同时工作,每个进程花费更长的时间,基本上减慢了一切。

在实际部署中 - 您不会以这种方式处理子任务的CPU密集型任务 - 您将使用理智的并发数据结构(如mqtt或数据库上的队列)并将工作分发给您部署的工作人员然后将其发送回服务器。

原因是服务器总是可以停机 - 而且你想要防止部分工作。

  

我的想法是检查当前进程是否低于某个限制(例如,一次限制为3个进程),如果超出限制,我将请求保存到数组中,并且每当当前进程低于限制,我使用.shift()弹出数组中最旧的一个并处理它。

以下代码执行此操作,我请求您阅读第一点在生产中使用该代码,而是在部署时限制该代码(例如,如果您使用AWS将规模限制为3个实例):

// lifted from my bluebird-api project
function throttle(fn, concurrency = 20, Promise) {
    // create an array of workers as resolved promises
    const workers = Array(concurrency).fill(Promise.resolve());
    const work = []; // pending work
    return function (...args) {
        // when there is work, pull the next worker
        const worker = workers.pop();
        if (worker === undefined) { // if there is no pending worker
            let resolve, reject;
            // store the promise for the result
            const promise = new Promise((res, rej) => {
                resolve = res; 
                reject = rej;
            });
            // and add it to the queue
            work.unshift({ args, resolve, reject, promise });
            return promise;
        }
        // after the worker is ready, call the function
        worker = worker.then(() => (fn(...args), null));
        worker.then(function pump() {
            if (work.length) { // after you're ready
                const {resolve, reject, args} = work.pop();
                // continue draining the queue
                worker = worker.then(() => fn(...args)).then(resolve, reject).then(pump);
            } else { // or declare ready
                workers.push(worker);
            }
            return null;
        });
        return worker;
    }
} 

代码从仍为WIP的bluebird-api解除。

  

如果您希望持有承诺并在将来向客户承诺承诺,那么正常的方法是什么?

是的,它完全是受支持的案例 - 并且它不会泄漏内存并且是安全的(在现代承诺实施中)。虽然再次 - 这是一个XY问题 - 您不应该在节点服务器上以这种方式分配工作。

当您实现正确的解决方案(排队和卸载到不同的服务)时,您可以创建一个promises队列,您可以在其中返回一个promise并在队列准备好后再解析它。

答案 1 :(得分:1)

  
      
  1. 我们能否保留未来使用的承诺? 2.我们将它们保存在数组中吗?
  2.   

你可以在一个数组中存储一个Promise,这是承诺的一部分,它们在需要之前不需要进行评估。

  
      
  1. 我应该使用其他方法来保持承诺,例如,使用sleep()或只是一个while循环来等待这个过程继续进行?
  2.   

使用睡眠没有错。不要循环效率低下。

修改

@Bergi在评论中说,即使在承诺sleep中也不应该使用。