当前位置: 首页 > 知识库问答 >
问题:

Javascript异步函数“等待”的正确心智模型:生成器的“屈服”与“promise”。那么()?

欧阳君浩
2023-03-14

发电商的收益和promise中的哪一个。那么()是理解“等待”的更为正确的思维模式吗?

属性比较,通过使用调试器遍历下面的代码段来推断:

等待:

>

等待promise实现。

等待表达式将函数的其余代码包装在一个微任务中。

发电机产量:

  1. yield暂停正在运行的函数的执行。发电机功能不“运行到完成”
  2. yield promise确保在执行剩余代码之前已结算promise
  3. yield不会包装或创建微任务

许诺然后(回调):

  1. 不会暂停正在运行的函数的执行
  2. 在执行回调之前,等待promise解决
  3. 创建微任务(回调)
//promise returning function
function foo(whoCalled) {
   let p = new Promise(function(resolve, reject) { 
     setTimeout( () => {
       console.log('resolving from setTimeout - called by: ' + whoCalled)
       resolve('resolve value') }, .1)
   })
   return p
}

//async await
async function asyncFunc() {
  await foo('async function')
  //rest of running function’s code…
  console.log('async function howdy')
}

//generator yield:
function* gen() {
   yield foo('generator function')
   //rest of running function’s code…
   console.log('generator function howdy')
}

//promise.then():
function thenFunc() {
   let r = foo('promise.then function').then(() => {
       //rest of running function’s code…
       console.log('promise.then() howdy')
   })
   return r
}

//main
function main() {

  //async await
  var a = asyncFunc() 
  console.log(a) //logs Promise { <pending> }
                 //the rest of the code following await foo() runs as a microtask runs once foo() resolves. The call stack was cleared.

  //generator
   var g = gen()
   console.log(g) // logs Object [Generator] {}
   var p = g.next().value
   console.log(p) //logs Promise { <pending> }
   g.next()       //the rest of the code following yield running gen function's code runs. call stack was not cleared.

   //promise.then()
   var x = thenFunc()
   console.log(x) //logs Promise { <pending> }
                   //the then(callback) microtask runs once foo() resolves. The call stack was cleared
}
main()
console.log('main is off the call stack - launch/startup macrotask completing. Event loop entering timer phase.')

除此之外,等待在引擎盖下做什么的准确心理模型是什么?

在最新ECMAScript规范中等待参考:https://www.ecma-international.org/ecma-262/10.0/index.html#await

在V8源代码中等待:https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-async-function-gen.cc#L252

共有3个答案

昝存
2023-03-14

我不知道这里正确的心理模型的答案,尽管我真的很想知道。

但我觉得这很有趣

《你不知道JS》一书的作者凯尔·辛普森(Kyle Simpson)插话了Wait如何在r/Javascript reddit上工作——来源:

”这是完全不正确的。生成器不会运行到完成,大多数异步等待的引擎实现实际上将它们视为生成器。当遇到屈服时,生成器会在本地暂停...字面意思。等待使用相同的方法。"

“不,这完全是胡说八道。大多数引擎将async await视为一个生成器,它肯定会在局部出现停顿。围绕后续代码包装promise.then()将是实现await的最幼稚、最低效的方法之一。即使引擎做到了这一点(大多数引擎没有做到)这并不意味着这是正确的思维方式。模型像屈服一样的局部停顿是合适的思维模式。"

但是,当我亲自查看ECMA脚本规范,并使用vscode nodejs调试器遍历代码时,wait似乎更类似于。然后()

邵逸明
2023-03-14

promise和让步不是最容易把握的,尤其是当你不知道它们在幕后是如何运作的时候。让我们从基础开始。首先要了解的是Javascript是单线程的,这意味着它只能同时做一件事。您仍然能够“一次”完成多个任务的方式是因为html" target="_blank">javascript有一个称为事件循环的东西。

事件循环基本上如下所示:

while(queue.waitForTasks()) {
   queue.performNextTask();
}

事件循环的作用是检查是否有新的“任务”供Javascript运行。如果有任务。然后执行它,直到没有更多的任务要执行为止。它将等待新的任务。这些任务存储在称为队列的东西中。

promise,异步/等待

现在我们了解了Javascript如何处理不同的任务。它如何与promise和异步/等待一起工作?promise只不过是一个任务,或者在Javascript中包含一个任务,它将被添加到队列中,并在所有任务执行完毕后执行。。then()是一种为promise提供回调的方法,一旦调用resolve回调,promise就会执行。

wait[something]关键字告诉Javascript,嘿,把下一个[something]放在队列的末尾,等[something]有结果后再联系我。

具有async关键字的函数基本上是在告诉Javascript:这个函数是一个promise,但是要立即执行它。

使用两个不同的异步函数a和B,异步函数的流程最容易掌握/演示,如下所示:

const A = async () => {
    console.log(A: Start);
    for (var i = 0; i < 3; i++) {
        await (async () => console.log('A: ' + i));
    }
    console.log('A: Done');
}
const B = async () {
    console.log(B: Start);
    for (var i = 0; i < 3; i++) {
        await (async () => console.log('B: ' + i));
        await (async () => {/* A task without output */});
    }
    console.log('B: Done');
}

当您使用wait调用函数时,如下所示:

console.log('Executing A');
await A();
console.log('Executing B');
await B();

这将导致:

Executing A
A: Start
A: 0
A: 1
A: 2
A: Done
Executing B
B: Start
B: 0
B: 1
B: 2
B: Done

和运行:

console.log('Executing A');
A();
console.log('Executing B');
B();

将导致:

Executing A
A: Start       Note: still gets ran before Executing B
Executing B
B: Start
A: 0
B: 0
A: 1
A: 2           Note: A: 2 first because another task in B was put in the queue
A: Done
B: 1
B: 2
B: Done

了解这一点可能有助于更好地了解应用程序的流程。

产量

yield关键字类似于await,意思是“外力”控制功能继续流动的时间。在这种情况下,不是promise任务的完成,而是生成器。next()函数

龙玄天
2023-03-14

这不是一个或另一个。实际上这是他们两个在一起:async/等待=产生然后一个运行程序。

异步函数会被等待关键字挂起,就像生成器函数*会被收益关键字挂起一样。执行流程在控制流语句中间停止和恢复的机制完全相同。

不同之处在于这些延续是如何驱动的,以及函数返回的内容。生成器函数在调用时创建生成器对象,您必须从外部显式调用next()方法,才能通过yield运行代码yield。另一方面,异步函数创建promise,并自行管理执行。它不等待外部next()调用,而是尽快运行每个异步步骤。它不会从那些next()调用返回生成的值,而是promise。resolve()将等待的值转换为promise,并调用其方法,然后将continuation作为回调传递。当到达返回时,它不会向调用方发出“迭代结束”的信号,而是用返回值解析最初返回的promise。

 类似资料:
  • MDN文档 异步/等待函数的目的是简化同步使用promise的行为,并对一组promise执行某些行为。正如promise类似于结构化回调一样,async/await类似于组合生成器和promise。 我了解异步/等待、生成器和promise的基本概念。然而,我不完全理解说async/await类似于将生成器和promise结合起来意味着什么。 所以async/wait简化了生成器和promise

  • 我正在研究ES9中提出的异步生成器,以便能够掌握逻辑。 因为每个产生的值都被用作返回对象中的值属性——由Promise包装——来自下一个()调用: 我认为这对我的promise也是正确的: 因此,这些promise被合并在一起。这听起来并不坏,但我并不认为这是因为: 那么,关键字wait与关键字yield在同一个表达式中使用完全无用,还是我遗漏了一些重要的内容?

  • 我正在研究promsies和async/await的用法。 我编写了以下代码,它执行以下操作: 它获取一些数据库数据(使用Knex.js), 处理该数据, 将处理的数据分配到指定的属性中 这3个步骤执行了多次(在下面的代码中,执行了两次),并且始终等待执行: 现在,我正在尝试编写与等效的promise链,这就是我想到的: 但这不太管用。发生的是,在第一个返回之后,中的结束了它的等待,这导致返回-并

  • 我试图理解为什么这段代码返回“Promise{pending}”。 当我通过reduceDirections()函数时,我可以看到我得到了想要的结果。但是当我(一行之后)时,我会改为“Promise pending” 很抱歉,我不理解promise和异步等待。我曾尝试在mdn上阅读和观看视频,但我不知道如何将它们显示的内容转移到这个问题上。提前感谢您的帮助!

  • 问题内容: 承诺和生成器允许您编写异步代码。我不明白为什么在ECMA脚本6中同时引入了这两种机制。什么时候最好使用Promise?什么时候使用生成器? 问题答案: 这两种技术之间没有对立。它们共存并很好地互补。承诺使您能够获得尚不可用的异步操作的结果。它解决了厄运金字塔问题。所以代替: 你可以写: 但是即使有承诺,您也必须以异步方式编写代码- 您必须始终将回调传递给函数。编写异步代码比同步代码难得

  • 问题内容: 我知道这个问题以前曾被问过,但是所有解决方案都不适合我。 我有一个将参数发送到API的函数,并以列表的形式返回数据。我有一个UITableView设置为使用该列表,但是它在列表分配给变量之前运行。 码: 如果不立即将其作为重复投票,我将不胜感激,这是我尝试的方法。 派遣组 信号量计时 运行变量 其中包括= self和= self 。 编辑:要求提取项目, 问题答案: 您不能-也不应该-