草庐IT

javascript - 询问不能直接转换为手动实现的异步迭代的异步生成器的示例

coder 2024-05-16 原文

异步生成器使用 internal queue处理同步的nextthrowreturn 方法调用。

我试图构建一种情况,其中此队列对于迭代本身的成功是强制性的。因此,我正在寻找一些手动实现异步迭代接口(interface)而不自定义重新实现队列的情况。

下面是一个例子,但不是很好,因为没有保持一般的时间一致性,但每一步的迭代结果都是正确的:

function aItsFactory() {
    let i = 1;
    return {
        async next() {
            if(i > 5) return Promise.resolve({ value: void 0, done: true });
            const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x => x.json());
            return Promise.resolve({ value: res, done: false });
        },
        [Symbol.asyncIterator]() { 
            return this;
        }
    }
}

const ait = aItsFactory();


// general time consistency is lost, because e.g. the fourth call
// is started with the previous three and it could end before the others.

// But the 'i' state is correctly shared so the fifth call
// is correctly requesting the element number five to the source
// and the last call will correctly receive { done: true }

;(async () => {
      ait.next();
      ait.next();
      ait.next();
      ait.next();
      console.log(await ait.next()); // { done: false, value: { userId: 1, id: 5, title: ... } }

      console.log(await ait.next()); // { done: true, value: undefined }
})();

可以说,如果没有适当的队列,迭代概念本身就会丢失。这是因为 active 并行 next 调用。

无论如何,我想找一些例子,也是微不足道的例子,这些例子清楚地表明异步生成器是创建格式良好的异步可迭代对象的更好方法,而不是手动实现异步迭代接口(interface).

------ 编辑 ------

让我们谈谈改进的情况:

function aItsFactory() {
    let i = 1;
    let done = false;

    return {
        async next() {

            if (done) return Promise.resolve({
                done: true,
                value: undefined
            });

            const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x => x.json());

            if (Object.keys(res).length === 0) { // the jsonplaceholder source is out of bounds
                done = true;
                return Promise.resolve({
                    done: true,
                    value: undefined
                });
            } else {
                return Promise.resolve({
                    done: false,
                    value: res
                });
            };

        },
        [Symbol.asyncIterator]() {
            return this;
        }
    }
}

const ait = aItsFactory();

// now lot of sync call to 'ait.next'

这里的done 解析是完全异步的。 从异步迭代的 Angular 来看,代码是错误的,因为每个 next 调用都应该被强制 await 前一个的结果,以了解它是否是最后一个有效的迭代。在这种情况下,当前的 next 应该什么也不做,立即返回 Promise.resolve({done:true, value:undefined})。 这要归功于同步 next 调用队列。

但在实践中,越界、重复调用 ait.next() 的主要风险是一些无用的 AJAX 请求。 别误会,我不是说我们可以视而不见。 关键是异步迭代本身的每一步都不会被破坏。

我希望看到一种不太不现实的情况,如果所有 next 调用都没有排队,迭代本身可能在每一步都受到影响。

最佳答案

以下场景:

您有一个数据集流进来,例如来自一些 API。你想对每个数据集做一些繁重的计算,这就是你将数据集发送给另一个工作人员的原因。但有时 API 可能会一次发送多个数据集,而您不希望同时运行很多 worker,而是希望有有限数量的 worker。在该数据集中,您正在搜索特定结果。使用异步迭代器,您可以将其编写为:

 const incoming = createSomeAsyncIterator();

  async function processData() {
    let done, value;
    while(!done) {
      ({ done, value } = await incoming.next());
      if(!done) {
        const result = await searchInWorker(value);
        if(result) {
           incoming.return();
           return result;
        }
      }
    }
 }

 // Consume tasks in two workers.
 Promise.race([
   processData(), processData()
 ]).then(gold => /*...*/);

如果 .next() 不按顺序返回数据集,上面的代码将失败。然后,尽管搜索已经完成,其中一名工作人员可能仍会继续。或者两个工作人员可能在同一个数据集上工作。


或者限制速率的例子(从 Bergi 那里偷来的 :)):

 async function* rateLimit(limit, time) {
   let count = 0;
   while(true) {
     if(count++ >= limit) {
       await delay(time);
        count = 0;
      }
      yield; // run api call
   }
 }

const userAPIRate = rateLimit(10, 1000);
async function getUser(id) {
  await userAPIRate.next();
  return doCall("/user/", id);
}

或者假设您想在某种形式的图库中显示图片流(在 React 中):

 const images = streamOfImages();

const Image = () => {
  const [image, setImage] = useState(null);
  useEffect((async ( ) => {
     if(image) await delay(10000); // show image at least 10secs
    const { value } = await images.next();
    setImage(value);
  }, [image]);

    return <img src={image || "loading.png"} />;
 };

const Gallery = () => <div>
  <Image /> <Image /> <Image />
 </div>;

还有一个,将数据调度到一个 worker 上,这样一个进程一次运行:

  const worker = (async function* () {
    let task;
    while(true) task = yield task && await doInWorker(task);
  })();

 worker.next();

 worker.next("task 1").then(taskOne => ...);
 worker.next("task 2").then(taskTwo => ...);

关于javascript - 询问不能直接转换为手动实现的异步迭代的异步生成器的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57578972/

有关javascript - 询问不能直接转换为手动实现的异步迭代的异步生成器的示例的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby-on-rails - 如何在 Rails 3 中创建自定义脚手架生成器? - 2

    有这些railscast。http://railscasts.com/episodes/218-making-generators-in-rails-3有了这个,你就会知道如何创建样式表和脚手架生成器。http://railscasts.com/episodes/216-generators-in-rails-3通过这个,您可以了解如何添加一些文件来修改脚手架View。我想把两者结合起来。我想创建一个生成器,它也可以创建脚手架View。有点像RyanBates漂亮的生成器或web_app_themegem(https://github.com/pilu/web-app-theme)。我

  5. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  8. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  9. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  10. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

随机推荐