【问题标题】:Calling function with a Promise hangs when in a loop在循环中使用 Promise 调用函数会挂起
【发布时间】:2017-08-16 08:44:07
【问题描述】:

当您运行以下 javascript 代码时,它可以正常工作。但是如果你删除 setTimeout 函数调用并用如下代码行替换它:

resolve(x);

浏览器将挂起。

浏览器似乎挂起,因为它正在无限循环中处理对 processNode 函数的调用。但不清楚的是为什么会发生任何阻塞。 processNode 返回一个 Promise。此外,startNodeProcessing 是一个异步函数,它在调用中使用 await。我认为通过使用带有等待的 Promise 和 async 函数可以防止线程的任何阻塞,但显然我错了。看来 setTimeout 只是在单独的线程上执行其代码,从而防止阻塞。但如果是这种情况,为什么要从 Promise 或 async 函数开始呢?

function processNode(x) {
    return new Promise(resolve => {
        console.log("X: " + x + "  " + Date.now());
        setTimeout(() => {
            resolve(x);
        }, x);
    });
}

async function startNodeProcessing() {
    while(true) {
        var a = processNode(1);
        var b = processNode(1);
        var c = processNode(1);
        var d = processNode(1);
        var a1 = await a;
        var b1 = await b;
        var c1 = await c;
        var d1 = await d;
    }

    return;
}

startNodeProcessing();

【问题讨论】:

  • 因为它产生的请求越来越多,这会使浏览器过载,并在一定时间内达到内存边界。
  • startNodeProcessing 函数中使用while 循环的目的是什么?注意,在使用await之前调用返回Promise的函数
  • JavaScript 是单线程的。 setTimeout 中的代码虽然是异步运行的,但仍然会阻塞主线程。
  • 类似的代码会很有趣
  • @Frxstrem 但是 setTimeout 中的代码不会阻塞主线程,我真的怀疑无论 setTimeout 中的工作需要多长时间才能完成。

标签: javascript promise


【解决方案1】:

接下来会发生:

 var a = processNode(1);
//the parser jumps to processNode and creates a promise:
return new Promise(function(resolve)
//the promise is resolved
resolve(x);
//the function returns, we enter the main function again:       
var a1 = await a;
//await internally calls the then function:
a1.then(return to this func)
//as the promise is resolved, the then callback is called immeadiately
//the parser returns to the main function

如您所见,解析器永远不会退出循环,因此它是阻塞的,因为它永远不会停止。

【讨论】:

  • 我更正了我的代码示例。我实际上的意思是 resolve(x) 而不是 var x = 0;
【解决方案2】:

此外,startNodeProcessing 是一个异步函数,它是 在调用中使用 await。

不,await 不用于通话。呼叫在await 之前的行进行。见serial await requests in a return run in parallel?


它在没有 setTimeout 的情况下阻塞。只需将 setTimeout 替换为 resolve(x) 它将阻塞。我正在尝试了解原因。

因为Promise构造函数executor函数被立即调用,例如,问题的Promise构造函数中的console.log()被立即调用,而不管是否或何时调用resolve函数参数。

Promise(resolve => {
   console.log("this is not executed asynchrously"); 
   resolve(1)
})

Promise

语法

new Promise( /* executor */ function(resolve, reject) { ... } );

参数

执行者

使用参数 resolve 和 reject 传递的函数。这 executor 函数由 Promise 立即执行 实现,传递解析和拒绝函数(执行者是 在 Promise 构造函数之前调用,甚至返回创建的 对象)。

【讨论】:

  • 从技术上讲这是对的,但这并不重要,因为您的回答没有回答问题。
  • @AndroidDev 你有什么问题?您还没有明确定义您要达到的目标吗?指出现有代码使用await 的一个问题,即在返回Promise 的函数已经被调用后使用await,完全否定@​​987654336@ 的功能。先说明while循环的目的,然后马上调整await的用法。
  • 它在没有 setTimeout 的情况下阻塞。只需将 setTimeout 替换为 resolve(x) ,它就会阻塞。我试图理解为什么。
  • @AndroidDev 因为Promise构造函数executor函数被立即调用,例如Promise构造函数中的console.log()。本质上Promise(resolve => resolve()) 不是异步的,setTimeout() 是异步的。
  • @AndroidDev 简而言之,Question 的代码存在几个问题。尽管应该在阅读您尝试使用的实现文档时找到您特定问题的答案。
猜你喜欢
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 2019-06-04
  • 2018-01-21
  • 2017-07-28
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
相关资源
最近更新 更多