递归承诺会导致堆栈溢出吗? [英] Recursive promises can cause stack overflow?

查看:105
本文介绍了递归承诺会导致堆栈溢出吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我发现了一些基于Promise的api库,我需要在一定时间间隔(无限次)(例如通常的后端循环)中使用此库发出api请求。该api请求-实际上是承诺链。

For example I found some api library that is based on promises, and I need to issue api requests using this library in some interval, infinite times (like usual back-end loop). This api requests - actually chain of promises.

因此,如果我编写如下函数:

So, if I write function like:

function r(){
    return api
        .call(api.anotherCall)
        .then(api.anotherCall)
        .then(api.anotherCall)
        ...
        .then(r)
}

我想出的解决方案是使用setTimeout递归调用 r

Solutions that I come up with is to use setTimeout for a call of r recursively.

function r(){
    return api
        .call(api.anotherCall)
        .then(api.anotherCall)
        .then(api.anotherCall)
        .then(()=>{setTimeout(r, 0)})
}

所以setTimeout实际上仅在调用堆栈为空时才调用 r

So setTimeout will call r actually only when call stack is empty.

这是一个很好的解决方案,还是有一些标准的递归调用承诺的方法?

Is it good solution, or there is some standard way of calling promises recursively?

推荐答案


此原因stackoverflow?

Will this cause stackoverflow?

不,不会。根据promise规范, .then()等待堆栈完全展开,然后在清除堆栈后调用(基本上在事件循环的下一个计时周期)。因此, .then()已经在当前事件完成处理并取消堆栈后被异步调用。您不必使用 setTimeout()来避免堆栈堆积。

No, it will not. Per the promise specification, .then() waits for the stack to completely unwind and is then called after the stack is clear (essentially on the next tick of the event loop). So, .then() is already called asynchronously after the current event is done processing and the stack is unwound. You do not have to use setTimeout() to avoid stack build-up.

您的第一个代码示例将没有任何堆栈堆积-up或堆栈溢出,无论您重复多少次。

Your first code example will not have any stack build-up or stack overflow, no matter how many times you repeat it.

Promises / A +规范,第2.2.4节说:

In the Promises/A+ specification, section 2.2.4 says this:


2.2.4在执行上下文之前,不得调用onFulfilled或onRejected堆栈仅包含平台代码。 [3.1]。

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

然后,平台代码在3.1中定义:

And, "platform code" is defined here in 3.1:


平台代码表示引擎,环境和Promise实现代码。实际上,此要求可确保在调用事件循环之后,使用新堆栈异步执行onFulfilled和onRejected。可以使用宏任务机制(如setTimeout或setImmediate)或微任务机制(如MutationObserver或process.nextTick)来实现。由于promise实现被视为平台代码,因此它本身可能包含任务调度队列或在其中调用处理程序的蹦床。

"platform code" means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a "macro-task" mechanism such as setTimeout or setImmediate, or with a "micro-task" mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or "trampoline" in which the handlers are called.




ES6 Promise规范使用不同的词,但产生相同的效果。在ES6中,通过将作业入队,然后让该作业得到处理,并仅在没有其他代码正在运行且堆栈处于运行状态时才进行处理,来执行promise .then()

这是 ES6规范


Job是一种抽象操作,可启动ECMAScript计算当前没有其他ECMAScript计算正在进行时。可以定义Job抽象操作以接受任意一组Job参数。

A Job is an abstract operation that initiates an ECMAScript computation when no other ECMAScript computation is currently in progress. A Job abstract operation may be defined to accept an arbitrary set of job parameters.

仅当没有运行的执行上下文且 execution上下文堆栈时才可以启动Job的执行为空。 PendingJob是对将来执行作业的请求。 PendingJob是内部记录,其字段在表25中指定。启动作业的执行后,作业将始终执行到完成。在当前运行的作业完成之前,无法启动其他作业。但是,当前运行的Job或外部事件可能会导致其他PendingJob排队,这些附加PendingJob可能在当前运行的Job完成后的某个时间启动。

Execution of a Job can be initiated only when there is no running execution context and the execution context stack is empty. A PendingJob is a request for the future execution of a Job. A PendingJob is an internal Record whose fields are specified in Table 25. Once execution of a Job is initiated, the Job always executes to completion. No other Job may be initiated until the currently running Job completes. However, the currently running Job or external events may cause the enqueuing of additional PendingJobs that may be initiated sometime after completion of the currently running Job.

这篇关于递归承诺会导致堆栈溢出吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆