保存JavaScript Promise以备将来使用

保存JavaScript Promise以备将来使用,javascript,node.js,promise,Javascript,Node.js,Promise,我正在使用Node.js来构建服务器端RESTApi。当我自己测试时,节点运行良好。但当它真的存在时,它仍可能面临溢出问题。当有很多请求时,比如说有5个以上的子进程(spawn)同时工作,每个进程都会花费更长的时间,基本上会减慢一切 我的想法是检查当前进程是否低于某个限制(例如,一次限制为3个进程),如果超过限制,我将请求保存到一个数组中,每当当前进程低于限制时,我使用.shift()弹出数组中最旧的进程并处理它 然而,当谈到承诺时,它变得很困难,因为我不知道我们是否可以将承诺存储到数组中,或者

我正在使用Node.js来构建服务器端RESTApi。当我自己测试时,节点运行良好。但当它真的存在时,它仍可能面临溢出问题。当有很多请求时,比如说有5个以上的子进程(spawn)同时工作,每个进程都会花费更长的时间,基本上会减慢一切

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

然而,当谈到承诺时,它变得很困难,因为我不知道我们是否可以将承诺存储到数组中,或者我是否应该让过程暂停几秒钟,我认为这不是一个好主意

如果你想保持承诺并在将来将承诺返还给客户,通常的方式是什么

对不起,我没有说清楚。以下是我的疑问总结: 1.我们能保留一个承诺以备将来使用吗? 2.我们是否将它们保存在数组中? 3.我是否应该使用其他方法来兑现承诺,比如使用sleep()或简单地使用while循环来等待这个过程继续进行

谢谢大家!

  • 我们能保留一个承诺以备将来使用吗?2.我们是否将它们保存在数组中
  • 您可以将承诺存储在一个数组中,这是承诺之美的一部分,在需要之前不需要对其进行评估

  • 我是否应该使用其他方法来兑现承诺,比如使用sleep()或简单地使用while循环来等待这个过程继续进行
  • 使用睡眠没有什么错。不要循环这是低效的

    编辑

    @Bergi在评论中说,即使在承诺中,睡眠也不应该被使用

    假设有超过5个child_进程(spawn)同时工作,每个进程都需要更长的时间,基本上减慢了一切

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

    原因是服务器总是会停机,您需要防止部分工作

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

    下面是这样做的代码,我请求您阅读第一点,不要在生产中使用该代码,而是在部署时限制该代码(例如,如果您使用AWS将扩展限制为3个实例):

    代码从仍为在制品的代码中提取

    如果你想保持承诺并在将来将承诺返还给客户,通常的方式是什么

    是的,它完全是一个受支持的案例——并且它不会泄漏内存,而且是安全的(在现代promise实现中)。尽管这也是一个XY问题,但您不应该在节点服务器上以这种方式分发工作


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

    承诺本身就是一种代表未来价值的结构。在创建后的任何时候,当您调用
    然后(cb)
    时,它都会为您提供值。如果我使用loadash会有帮助吗?您是否考虑过在流程中使用
    承诺队列
    包?是的,承诺一个简单的值,可以像其他任何程序一样传递。听起来您需要一个更强大的服务器,或者找到并修复性能瓶颈。仅仅排队请求通常不会有帮助——这些队列最终也会溢出。管理它们需要额外的处理能力和内存,因此通常最好尽快为它们提供服务。
    sleep
    听起来像是一种同步阻塞方法,这与loop@Bergi我认为OP的意思是在承诺中睡觉“在承诺中”并不意味着“在背景中”。你根本不应该睡觉。所以在现实世界中,“子进程”通常在不同的服务器实例中?我实际上在后面使用child_进程来运行python。有更好的方法吗?在“现实世界”中,您通常会在容器中执行所有这些操作,而运行python将在从队列馈送的不同容器中运行—这样您可以“弹性地”扩展python进程实例的数量。
    // 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;
        }
    }