【问题标题】:Why doesn't this run asynchronously (for with Promise inside)? [duplicate]为什么这不异步运行(因为里面有 Promise)? [复制]
【发布时间】:2021-06-19 14:11:39
【问题描述】:

我是 javascript 的新手,我一直在学习 Promise,最近我开始研究一些简单的列表,该列表以随机延迟 (setTimeout) 检索,我认为这是一个经典的。在尝试并进行了一些研究之后,我发现我发布的帖子对我有很大帮助,而且效果很好,但是在查看了该帖子对我所做的建议之后,我注意到差异是两个括号......我一直在阅读和试图理解为什么括号会产生如此大的差异(两个选项都有效),但我不明白。

有人能解释一下有什么区别吗?我提到的括号在函数 loadIng() 的第 5 行和第 12 行中,第一行的左括号和第二行的右括号。

{
    new Promise(resolve => {
    ...
    })
}

如果我运行带括号的代码,它会同步运行,但如果我不带括号运行它,它会异步运行......我真的不明白。

function loadIngs() {
    p = Promise.resolve();
    for (let [k, v] of someArray) {
        p = p.then(() => 
            {new Promise(resolve => { //this
                delay = Math.random() * 2000;
                console.log(`${k}:${v} comes delayed for ${delay}`)
                setTimeout(() => {
                    console.log("executes some function")
                    resolve();
                }, delay);
            })} //this
        );
    }
}

【问题讨论】:

  • 嗨,我建议生成minimal reproducible example - 意思是 - 删除所有与您的代码不直接相关的代码。这包括您提供的所有 HTML 和 CSS 以及大部分 JS 脚本。通过编写一个简洁的示例,我们可以更轻松地为您提供帮助。
  • 请展示一个异步运行的可运行示例。您引用的括号似乎是函数定义的一部分(尽管尚不清楚您在谈论代码中的哪个示例),因此只要调用该函数,代码就会运行。
  • 如果您在谈论new Promise() 函数中的loadIngs(),那么括号是可选的。可以使用或不使用括号声明单个语句箭头函数体。这是一个简单的例子:setTimeout(() => console.log("hi"), 100)setTimeout(() => { console.log("hi") }, 100)。这些是同一回事。这里的这两段代码没有同步/异步的区别,也没有任何执行上的区别。
  • @jfriend00 确认同样的事情,我签入调试器始终提供异步,同时在文档中明确写入 The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. 括号是可选的,如果您使用它们超过一行如果没有脚本,请不要使用它们。
  • 你需要returnp = p.then(() => …)链中的promise,否则函数不会链接任何东西。除非您添加 return 关键字,否则带大括号的语法将返回 undefined

标签: javascript es6-promise curly-braces asynchronous-javascript


【解决方案1】:

这里的区别与箭头函数的自动返回值有关,该箭头函数在单个语句函数体周围不使用括号。

如果您在谈论 loadIngs() 函数中的 new Promise(),请点击此处:

function loadIngs() {
    p = Promise.resolve();
    for (let [k, v] of ings) {
        p = p.then(() => 
            {new Promise(resolve => {
                delay = Math.random() * 2000;
                console.log(`${k} comes delayed for ${delay}`)
                setTimeout(() => {
                    setIng(k, v);
                    resolve();
                }, delay);
            })}
        );
    }
}

那么new Promise() 周围的括号是可选的。

单个语句箭头函数体可以用括号声明,也可以不带括号声明。这是一个简单的例子:

setTimeout(() => console.log("hi"), 100) 

setTimeout(() => { console.log("hi") }, 100)

这些几乎是一样的。由于函数体是单个语句console.log("hi"),因此箭头函数体可以独立存在,也可以用括号括起来。两者都可以,并为返回值生成相同的执行。如果你使用brackets,那么如果你想要一个特定的返回值,你就需要一个return 语句。如果没有括号,单个语句的value 会自动成为该箭头函数的返回值。

这个返回值在你的 Promise 示例中有所不同。因此,对于 loadIngs() 函数中的 p.then(() => ...) 结构。它可以是:

p.then(() => { return new Promise(...) })

也可以是:

p.then(() => new Promise(...) )

这两个执行相同。但是,请注意,这与您的代码中显示的并不完全相同。我在new Promise() 前面添加了return。当您删除 return 时,则:

p.then(() => { new Promise(...) })

箭头函数没有返回值。这意味着当您创建一个新的 Promise 时,您不会从 .then() 处理程序中返回它,因此它不会链接到父 Promise 链中,并且您会获得多个独立的 Promise 链。

这将造成执行差异,并且可能是您所说的“异步运行”时所说的原因。这并不完全是我要描述的方式,但它确实会在事情运行的时间上产生差异,因为在一种情况下,您有一个链接的 Promise 链,而在另一种情况下,您有两个独立的、独立的 Promise 链。

【讨论】:

  • "loadIngs() 函数中的 p.then(() => ...) 结构也是如此。它们执行相同。" - 不,它们绝对不会:你忘了失踪的return。一个函数返回一个将由then 链等待的承诺,另一个返回undefiend。这就是为什么这两个代码执行不同并导致不同结果的原因。
  • @Bergi - 当您发表评论时,已经在纠正该问题。
  • @jfriend00 谢谢你的帮助。我可以清楚地看到区别......我想我之前没有完全理解箭头函数的自动返回值。
  • @HugoRodríguez - 如果这回答了您的问题,那么您可以通过单击答案左侧的复选标记向社区表明这一点。这也将为您在此处遵循正确的程序赢得一些声誉积分。
猜你喜欢
  • 2021-01-15
  • 2021-05-19
  • 2020-04-18
  • 1970-01-01
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
  • 2016-07-27
相关资源
最近更新 更多