javascript - What is the difference between `for await` and awaiting a promise obtained from a synchronous iterable? - Stack Ove

I know there are plenty of resources explaining for await...of, but I don't think I'll ever f

I know there are plenty of resources explaining for await...of, but I don't think I'll ever fully grasp the concept until I see an example that works the exact same way but with more basic syntax.

Thing is, if my understanding is correct, these 2 for loops should behave the exact same way:

for(const p of iterableWithPromises) {
  const q = await p;
  // ...
}

for await (const q of iterableWithPromises) {
  // ...
}

Is that it? Is this syntax only saving us from creating a new variable inside the loop to store the promise's result?

I know there are plenty of resources explaining for await...of, but I don't think I'll ever fully grasp the concept until I see an example that works the exact same way but with more basic syntax.

Thing is, if my understanding is correct, these 2 for loops should behave the exact same way:

for(const p of iterableWithPromises) {
  const q = await p;
  // ...
}

for await (const q of iterableWithPromises) {
  // ...
}

Is that it? Is this syntax only saving us from creating a new variable inside the loop to store the promise's result?

Share Improve this question edited Nov 18, 2024 at 17:52 dumbass 27.3k4 gold badges38 silver badges74 bronze badges asked Nov 18, 2024 at 10:16 AdrianAdrian 2,0271 gold badge23 silver badges45 bronze badges 7
  • Related: Using for await...of with synchronous iterables – VLAZ Commented Nov 18, 2024 at 11:11
  • Does desugaring for await .. of answer your question? – Bergi Commented Nov 18, 2024 at 15:46
  • 1 What exactly is iterableWithPromises? If you are talking about a synchronous iterator yielding promises, then you should use neither - see the thread linked by VLAZ. – Bergi Commented Nov 18, 2024 at 15:49
  • @VLAZ That post might be related, but doesn't really showcase the thing that made me understand, which is the fact that for await should be used when you need the result of the promise to know if you should keep iterating if you don't want to face the caveats I mentioned in my answer. – Adrian Commented Nov 18, 2024 at 15:58
  • @Bergi The post you mention answers my question, but to some extent: It does show an equivalent with more basic syntax (in the question itself instead of the answers), but it would be nice if it also mentioned the caveats I talked about in my answer since that is what REALLY made me understand this. – Adrian Commented Nov 18, 2024 at 16:03
 |  Show 2 more comments

2 Answers 2

Reset to default 4

No, the 2 loops are not exactly equivalent.

First things first: This is, roughly speaking, what the equivalent of the traditional for ...of loop looks like with normal iterables (omiting corner cases like the usage of break, continue, exceptions and returns in the loop for brevity):

// Given this iterable...
const iterable = {
  [Symbol.iterator]() {
    console.log('[Symbol.iterator]() called');
    let i = 0;
    return {
      next() {
        console.log('next() called');
        const iteratorResult = { value: i, done: i > 3 };
        i++;
        return iteratorResult;
      },
    };
  },
};

// ...this for loop...
for (const value of iterable) {
  console.log(`VALUE: ${value}`);
}

// ...is equivalent to this while loop:
const iterator = iterable[Symbol.iterator]();
let iteratorResult = iterator.next();
while(!iteratorResult.done){
const value = iteratorResult.value;
  console.log(`VALUE: ${value}`);
  iteratorResult = iterator.next();
}

// And this would be the output:
//
// [Symbol.iterator]() called
// next() called
// VALUE: 0
// next() called
// VALUE: 1
// next() called
// VALUE: 2
// next() called
// VALUE: 3
// next() called

Now, then, with for await...of and async iterables, the equivalent would be like this:

const makePromise = (name, seconds, value) => {
  console.log(`Creating a promise named ${name} that will resolve in ${seconds} seconds with a value of ${JSON.stringify(value)}...`);
  return new Promise((resolve) => {
    console.log(`Promise ${name} created`);
    setTimeout(() => {
      console.log(`Resolving promise ${name}...`);
      resolve(value);
      console.log(`Promise ${name} resolved`);
    }, seconds*1000)
  });
}

// Given this iterable...
const iterable = {
  [Symbol.asyncIterator]() {
    console.log('[Symbol.asyncIterator]() called');
    let i = 0;
    return {
      next() {
        console.log('next() called');
        const iteratorResult = makePromise(`promise-${i}`, i, { value: i, done: i > 3 });
        i++;
        return iteratorResult;
      },
    };
  },
};

// ...this for loop...
for await (const value of iterable) {
  console.log(`VALUE: ${value}`);
}

// ...is equivalent to this while loop:
const iterator = iterable[Symbol.asyncIterator]();
let iteratorResult = await iterator.next();
while(!iteratorResult.done){
  const value = iteratorResult.value;
  console.log(`VALUE: ${value}`);
  iteratorResult = await iterator.next();
}

// And this would be the output:
//
// [Symbol.asyncIterator]() called
// next() called
// Creating a promise named promise-0 that will resolve in 0 seconds with a value of {"value":0,"done":false}...
// Promise promise-0 created
// (0 seconds later...)
// Resolving promise promise-0...
// Promise promise-0 resolved
// VALUE: 0
// next() called
// Creating a promise named promise-1 that will resolve in 1 seconds with a value of {"value":1,"done":false}...
// Promise promise-1 created
// (1 second later...)
// Resolving promise promise-1...
// Promise promise-1 resolved
// VALUE: 1
// next() called
// Creating a promise named promise-2 that will resolve in 2 seconds with a value of {"value":2,"done":false}...
// Promise promise-2 created
// (2 seconds later...)
// Resolving promise promise-2...
// Promise promise-2 resolved
// VALUE: 2
// next() called
// Creating a promise named promise-3 that will resolve in 3 seconds with a value of {"value":3,"done":false}...
// Promise promise-3 created
// (3 seconds later...)
// Resolving promise promise-3...
// Promise promise-3 resolved
// VALUE: 3
// next() called
// Creating a promise named promise-4 that will resolve in 4 seconds with a value of {"value":4,"done":true}...
// Promise promise-4 created
// (4 seconds later...)
// Resolving promise promise-4...
// Promise promise-4 resolved

Now let's say my initial wrong assumption about how this kind of for loop works was right. Then we should be able to replace the async iterable with a normal iterable, like so:

const iterable = {
  [Symbol.iterator]() {
    console.log('[Symbol.iterator]() called');
    let i = 0;
    return {
      next() {
        console.log('next() called');
        const iteratorResult = {
          value: makePromise(`promise-${i}`, i, i),
          done: i > 3
        };
        i++;
        return iteratorResult;
      },
    };
  },
};

If you run any example with this last iterable you will notice no difference in the results. Not even in the times between one output and the next. But there is something you should notice: The done property of the object returned by next() is included inside the promise when using for await...of. This is relevant in cases where deciding whether the for loop should stop iterating depends on the result of the promise.

For instance, let's say you have a REST api that has in one of the fields of the response json object a url to keep fetching the next results: You could still technically implement this with a normal iterator, but with a few caveats:

  • First, the first time next() is evaluated you are forced to make sure done is evaluated to true regardless of whether the REST api has actually any data or not to make sure at least the first request is made, otherwise no request would be made to begin with and you wouldn't have any way to tell if there is any data at all (if it evaluated to false, the request would still be done but the loop would end without any chance to do anything with the data and you won't be able to do anything about it).
  • Second, you will assume that the developer will always dutifully await each result in each iteration of the loop before reaching the next iteration. So, if a developer had the brilliant idea of not awaiting to make the requests run in parallel, then it would run an infinity loop that would only stop once the first promise finally resolves and updates the value of the done property for the first time. You can prevent this by fetching the data in the server implementing async iterators as I did in the examples (Notice how in the for await...of example I use [Symbol.asyncIterator] instead of [Symbol.iterator]) to force the developer to use for await...of and prevent these problems.

Of course. You are correct that the two loops share a similar purpose: they both iterate over an iterable containing promises and allow you to handle their resolved values. However, for await...of provides cleaner and more concise syntax specifically designed to handle asynchronous iterables, while your first example is a more verbose way of achieving the same result with a regular for loop.

Why use for await...of?

The for await...of loop is specifically useful when dealing with asynchronous iterables, which provide values over time, such as streams or generators that yield promises.

Example: Using an asynchronous generator

async function* asyncGenerator() {
  yield Promise.resolve(1);
  yield Promise.resolve(2);
  yield Promise.resolve(3);
}

(async () => {
  for await (const value of asyncGenerator()) {
    console.log(value); // Logs 1, then 2, then 3
  }
})();

This cannot be easily replicated with a for...of loop because for...of does not inherently understand asynchronous iterables.

And if you want to get the hood , go for the spec.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745626673a4636850.html

相关推荐

  • 推荐一个轻量级的监控平台并且支持移动端

    简介XUGOU 是基于Cloudflare构建的轻量化监控平台,专精于系统资源监控与可视化状态页面服务。该平台提供英文简体中文双语支持,满足全球化部署需求。面向开发者及中小团队,项目致力于提供高可用性的监控解决方案。核心功能与实现平台功能

    49分钟前
    00
  • module 'torch.

    踩坑Ascend, 安装 pytorch 2.5.1 和 pytorch_npu 2.5.1, import torch 报错.执行 python -c "import torch;import torch_npu;"时

    47分钟前
    10
  • 大模型驱动金融数据应用的实战探索

    近年来,人工智能技术的飞速发展正在重塑全球各行各业的生态格局,金融行业作为数据密集型领域,更是首当其冲。大模型凭借其强大的自然语言处理、逻辑推理和生成能力,逐渐成为金融数据应用的核心驱动力。本文将从行业背景与趋势、核心场景重构、产品能力提升

    44分钟前
    00
  • 拥抱国产化:转转APP的鸿蒙NEXT端开发尝鲜之旅

    本文由转转技术团队赵卫兵分享,原题“鸿蒙新篇章:转转 APP 的 HarmonyOS Next 开发之旅”,下文进行了排版优化和内容修订。1、引言2023 年在华为开发者大会(HDC.Together)上,除了面向消费者的 HarmonyO

    42分钟前
    00
  • 人工智能与ai有什么区别

    一、引言:概念之辨的必要性在科技浪潮席卷全球的当下,人工智能(Artificial Intelligence,简称AI)已成为人们耳熟能详的词汇。然而,当我们深入探讨时,会发现“人工智能”与“AI”这两个表述在语义和使用场景上存在微妙差异。

    39分钟前
    00
  • Nat. Mater.

    大家好,今天给大家分享一篇近期发表在Nat. Mater.上的研究进展,题为:De novo design of self-assembling peptides with antimicrobial activity guided

    36分钟前
    00
  • windows新建open ai密钥

    api链接 openai的api需要付费才能使用但好像系统变量不知道为啥用不了打印出来,获取到的是None可以用了

    35分钟前
    00
  • Windows系统密钥检测工具PIDKey 2.1中文版

    Windows系统密钥检测工具PIDKey 2.1中文版 【下载地址】Windows系统密钥检测工具PIDKey2.1中文版 Windows系统密钥检测工具PIDKey 2.1中文版是一款功能强大的工具,专为管理Win

    32分钟前
    00
  • 子网掩码是怎么“掩”的?用积木教你彻底搞懂!

    子网掩码是怎么“掩”的?用积木教你彻底搞懂!前言肝文不易,点个免费的赞和关注,有错误的地方请指出,看个人主页有惊喜。作者:神的孩子都在歌唱你是不是也曾被“子网掩码”这个术语搞得晕头转向?明明是学网络的第一步,却像是打开了数学世界的大门:2

    31分钟前
    00
  • 1.54G 雨晨 26100.3775 Windows 11 IoT 企业版 LTSC 24H2 极速版

    精简AERO外主题并增加一套壁纸主题(默认启用)误杀导致功能界面空白、因WMIC被默认移除系统可能会多次重启。 拒止连接 www.5909 拒止连接 www.mnpc 拒止连接 quark 拒止

    31分钟前
    00
  • ​2025 轻松部署 Odoo 18 社区版

    随着 Odoo 18 社区版的发布,越来越多的企业希望借助这款开源 ERP 系统实现数字化转型。本文将深入解析传统部署方式的底层逻辑,并揭示如何通过自动化工具实现零门槛快速部署。一、手工部署 Odoo 18 技术全解 Docker 环境搭建

    28分钟前
    00
  • Java&Activiti7实战:轻松构建你的第一个工作流

    本文已收录在Github,关注我,紧跟本系列专栏文章,咱们下篇再续!

    26分钟前
    00
  • 用Xshell8配置密钥登陆

    1.首先在服务端查看root.sshauthorized_keys是否存在,这是存储公钥的文件,若不存在需新建此文件 2. 打开Xshell8,选择"新建",选择"新建用户密钥生成向导" 给用户

    25分钟前
    00
  • 人工智能应用领域有哪些

    人工智能应用领域有哪些一、引言随着科技的飞速发展,人工智能(AI)已经逐渐渗透到我们生活的方方面面,成为推动社会进步的重要力量。从医疗健康到金融服务,从教育学习到智能制造,人工智能以其独特的技术优势,为各行各业带来了前所未有的变革。本文旨在

    25分钟前
    10
  • 【赵渝强老师】创建PostgreSQL的数据库

    在PostgreSQL中,创建数据库主要通过SQL命令“create database”完成,视频讲解如下:下面是具体的操作步骤。(1)查询现有数据库的集合,可以检查系统目录pg_database。代码语言:sql复制postgres=#

    22分钟前
    00
  • 设计模式:工厂方法模式(Factory Method)(2)

    当年做一个项目时,还不懂什么是设计模式,仅仅是按照经验完成了需求。回头看看,就是暗合桥接模式。但是,在整个需求实现过程中,甲方需要我在已经设计好的标准业务逻辑中添加非标的需求,因为,在他们眼里,从业务角度来看,是自然的拓展。如果当年我知道还

    20分钟前
    00
  • 「全球首个自回归视频生成大模型」,刚刚,Swin Transformer作者创业团队重磅开源!

    机器之心编辑部视频生成领域,又出现一位重量级开源选手。今天,马尔奖、清华特奖得主曹越的创业公司 Sand AI 推出了自己的视频生成大模型 ——MAGI-1。这是一个通过自回归预测视频块序列来生成视频的世界模型,生成效果自然流畅,还有多个版

    13分钟前
    00
  • Claude竟藏着3307种「人格」?深扒70万次对话,这个AI会看人下菜碟

    新智元报道编辑:定慧 英智【新智元导读】AI会无脑附和吗?Anthropic研究发现,Claude能根据场景切换人格:谈恋爱时化身情感导师,聊历史时秒变严谨学者。一些对话中,它强烈支持用户价值观,但在3%的情况下,它会果断抵制。想象一

    7分钟前
    10
  • 通过Windows镜像离线升级或修复Win10系统

    通过Windows镜像离线升级或修复Win10系统 导航 文章目录 通过Windows镜像离线升级或修复Win10系统导航关键条件与原理查询系统版本下载镜像打开镜像进行更新修复 关键条件与原理 版本一致性 需确保镜像的**SKU&am

    3分钟前
    10
  • Windows 10 LTSC 2019 中文版下载及安装教程(附安装包)

    (cn_windows_10_enterprise_ltsc_2019_x64_dvd_9c09ff24)涵盖常见疑问和注意事项: cn_windows_10_enterpr

    3分钟前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信