【问题标题】:Promise is blocking the thread [duplicate]承诺正在阻塞线程[重复]
【发布时间】:2021-07-10 14:08:18
【问题描述】:

我是 Node.js 的新手,正在尝试理解 asyncawait 术语。

在这个过程中,我了解了Promise

据我了解,借助它,我们可以使函数成为非阻塞的。

我尝试了以下代码,

function get() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            let out = 0
            const n = 9_900_000
            console.log('start looping')
            for (let i = 0; i < n; i++) {
                out += Math.cos(i)
            }
            console.log('done looping')
            resolve(out)
            console.log('resolved')
        })
    })
}

console.log('before function calling')
r = get()
console.log('After function calling')
r.then(console.log)
console.log('in the end of file')

我们发现 get 的行为类似于非阻塞函数


function get() {
    return new Promise((resolve, reject) => {

        let out = 0
        const n = 9_900_000
        console.log('start looping')
        for (let i = 0; i < n; i++) {
            out += Math.cos(i)
        }
        console.log('done looping')
        resolve(out)
        console.log('resolved')
    })
}
console.log('before function calling')
r = get()
console.log('After function calling')
r.then(console.log)
console.log('in the end of file')

换句话说,我删除了setTimeout

现在get 变成了一个阻塞函数。

为什么会这样?

【问题讨论】:

  • 传递给 promise 构造函数的函数被同步调用
  • Promise 不会在单独的线程或类似的线程上运行。承诺只是异步任务的通知机制。但是很多异步任务只是在同一个线程上运行。您编写的代码会阻塞线程一段时间,所以它会……阻塞线程一段时间。然后通过 Promise 发送通知。
  • JS 中没有“线程”,一旦一些同步代码(比如你的for)开始执行,它就会一直运行到完成。与此同时,其他代码将无法运行,因为 JS 实际上是单线程的......

标签: javascript node.js asynchronous async-await


【解决方案1】:

promise executor 函数是同步执行的,也就是说函数内部的代码如下:

new Promise(() => { // promise "executor function" that executes synchronously

});

在创建 Promise 时执行(该函数由 Promise 构造函数执行)。在您的第二个示例中,由于您的 for 循环是阻塞的,因此只有在您的 for 循环完成后才会创建承诺,并且只有在创建后才会从 get() 返回,从而阻止执行任何其他代码在您调用 get() 函数之后。

在你的第一个例子中,当你创建你的 Promise 时,promise executor 函数仍然同步运行,但是这一次,你调用 setTimeout()0 的延迟。这会使您传递给setTimeout() 的回调在task queue 上排队,并且只有在您的主脚本完成执行后才会执行。这意味着当您的 Promise 从您的 get() 函数返回时,您的 setTimeout() 回调中的 for 循环尚未开始运行,因为传递给 setTimeout() 的回调尚未执行/运行由于仍有代码需要在主脚本中运行。结果,您的其他代码(例如console.log()s)可以运行,因为没有任何东西阻止它们。只有在您的主脚本完成后,您的回调才会执行之前由 setTimeout 排队的回调。

请记住,Promises 不是使同步代码异步的工具,它们更像是帮助开发人员处理已经行为异步的代码的工具。如果您需要在后台线程中执行阻塞操作以防止阻塞主线程,那么您可以考虑使用web worker

【讨论】:

  • 谢谢,尼克。这很有帮助并解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-15
相关资源
最近更新 更多