Promise 正在阻塞线程

Shi*_*wal 2 javascript asynchronous node.js async-await

我是 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')
Run Code Online (Sandbox Code Playgroud)

我们发现它的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')
Run Code Online (Sandbox Code Playgroud)

换句话说,我删除了setTimeout.

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

为什么会发生这种情况?

Nic*_*ons 10

Promise 执行器函数同步执行,这意味着函数内部的代码如下:

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

});
Run Code Online (Sandbox Code Playgroud)

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

在您的第一个示例中,当您创建 Promise 时,Promise 执行器函数仍然同步运行,但这一次,您的调用setTimeout()延迟了0. 这使得您传递的回调在任务队列setTimeout()中排队,并且只有在主脚本执行完毕后才会执行。这意味着当您的 Promise 从您的函数返回时,您的 setTimeout() 回调内部的循环尚未开始运行,因为传递给的回调尚未执行/运行,因为仍然有代码需要执行/运行在主脚本中运行。因此,您的其他代码(例如s)可以运行,因为没有任何东西阻止它们。仅当主脚本完成后,之前由 setTimeout 排队的回调才会被执行。get()forsetTimeout()console.log()

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