Is it possible to achieve bidirectional communication using asynchronous JavaScript generators?

Utilizing JavaScript generators for two-way communication is a powerful feature, enabling capabilities similar to channels in CSP-based programming languages. You can learn more about this here.

However, when it comes to async generators, the process seems a bit unclear. For instance, let's consider the creation of an async generator using the following code:

async function* asyncGenFn() {
  yield Promise.resolve(true)
}

This function returns an AsyncIterableIterator, which lacks a next function like IterablIterator. This raises the question of whether it is possible to achieve two-way communication with async generators created in this manner, or if I am simply pursuing the wrong approach.

Answer №1

Let's explore the concept of 2-way communication using generators with a practical example -

const g = function* (x)
{ // initiating outbound message
  // receive inbound message in msg1
  const msg1 = yield "sending this out"
  
  // another outbound message
  // receive inbound message in msg2
  const msg2 = yield "sending this too" 
  
  // perform some action
  console.log(msg1, msg2)
  
  // finally, return a value
  // note: generators can take arguments like x here
  return x * 2
}

// create an instance of the generator
const iterator = g(100)

// retrieve the first value from the iterator
let val = iterator.next()

// prepare an example message to send to the generator
let m = 1

while (!val.done)
{ // log each outbound message received
  console.log("received message", val.value)
  
  // resume the generator by sending a message back "in"
  val = iterator.next(m)
  
  // update the example message
  m = m + 1
}

// display the final returned value
console.log("return value", val.value)

Output

received message sending this out
received message sending this too
1 2
return value 200

Understanding 2-way communication through problem-solving is essential. Generators provide pause/resume functionality, making them ideal for asynchronous tasks. While newer methods like async and await blend synchronous and asynchronous code seamlessly -

const delay = x =>
  new Promise(r => setTimeout(r, 1e3, x))

const main = async (z) =>
{ const x = await delay(200)
  const y = await delay(300)
  return x + y + z
}

main(100).then(console.log, console.error)
// Result after 2 seconds...
// => 600

Before async and await, we utilized generators for 2-way communication as demonstrated below with the run function. This approach allows us to structure our program similarly but with a generator function and yield statements -

const delay = x =>
  new Promise(r => setTimeout(r, 1e3, x))

const main = function* (z)
{ const x = yield delay(200)
  const y = yield delay(300)
  return x + y + z
}

const run = it =>
{ const loop = ({ done, value }) =>
    done
      ? Promise.resolve(value)
      : value.then(x => loop(it.next(x)))
  return loop(it.next())
}

run(main(100)).then(console.log, console.error)
// Result after 2 seconds...
// => 600

In the above snippet, run recursively processes generator output promises, feeding resolved values back into the generator until completion and providing the final result -

const run = it =>
{ const loop = ({ done, value }) =>
{
    if(done) {
        return Promise.resolve(value);
    } else {
        return value.then(x => loop(it.next(x)));
    }
}
return loop(it.next());
}

Prior to utilizing generators for mimicking coroutines, crafting asynchronous programs involved manually chaining .then calls throughout the codebase -

const delay = x =>
  new Promise(r => setTimeout(r, 1e3, x))

const main = z =>
  delay(200).then(x =>
  delay(300).then(y =>
  x + y + z
  ))
  
main(100).then(console.log, console.error)
// Result after 2 seconds...
// => 600

As demonstrated, leveraging generators for 2-way communication offers clarity and elegance in expressing complex programs. Although JavaScript introduces async/await for asynchronous operations, understanding approaches like the run function provides insights on achieving similar behavior without relying on these new keywords.

Answer №2

After some troubleshooting, I discovered that the root cause of the issue was related to my Typescript compilation settings. By including the following line in my tsconfig.json, the problem was resolved:

"compilerOptions": {
  "lib": ["esnext.asynciterable"]
}

I want to express my gratitude to those who assisted me in resolving this issue!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to authorizing a POST request using AWS Signature Version 4

My approach to the majority of the code was inspired by a Python example from AWS, which I adapted for JS/node. import axios from 'axios' import {createHash, createHmac} from 'crypto' import moment from 'moment' async ...

JavaScript Promise Fundamentals

While I am quite familiar with coding in JavaScript, the benefits of promises in the JS world still seem somewhat unclear to me. Below is an example of asynchronous calls using callbacks nested within each other. (function doWorkOldSchool() { setTime ...

When an asyncIterator is implemented in a unit test, it fails to resolve with any values

I am currently working with a readable stream from chatGPT and I am trying to assert it using an asyncIterator. However, despite my jest test running smoothly, there seems to be a logical error preventing it from resolving after each iteration. Can anyone ...

What are the steps for fetching data using ajax?

I am looking to create a function where a user can input a country and then view its population. The JavaScript code I have is supposed to take the user's input, search for the country when a button is clicked, and retrieve the population data from a ...

The webpage hosted on Heroku displays a blank background, requiring users to refresh the page with an F5 key

I developed a group chat program using Python microframework flask, vanilla JavaScript, and Flask-SocketIO. The program is deployed on heroku and can be accessed here: . After deployment, I encountered the following issue: While the program worked fine o ...

Using setInterval within componentDidUpdate

https://i.sstatic.net/Si1Up.png https://i.sstatic.net/6KUIL.png Hey there! I have a scenario in my app.js where, upon meeting a specific condition, I switch the value of my toPing state from false to true. This change is then checked in componentDidUpdate ...

Creating input fields in Angular 2

Can someone guide me on how to sum the values entered in two input fields? Here is my HTML code snippet. I'm not sure if there's anything missing in the ts file. <div class="small-7 columns"> <md-input-container> <input t ...

Create a music player application using the React context API

Here is a code snippet for implementing a music player using context: import React from 'react'; import { BarSongTitle, BottomBar, Button, PlayList, Song, SongTitle, } from './styles.js'; import { songList } from './con ...

Comparison between Microsoft's AJAX Toolkit and jQuery

Ever since the early days of Atlas, our team has relied on Microsoft's AJAX Toolkit for all our web development needs. It wasn't until recently that we stumbled upon the jQuery/Prototype phenomenon and realized what we had been missing out on. Th ...

Populate the attributes of an alpaca with a variable

Creating a form dynamically using Alpaca Forms is a requirement and the given code snippet serves as a starting point: $("#form").alpaca({ "schema": { "type":"object", "pr ...

Incorporating AngularFire2 in the latest Angular 11.0.5 framework

I have been attempting to utilize Firebase as a database for my angular application. Following the guidance provided in these instructions (located on the official developers Github page), I first installed npm install angularfire2 firebase --save in my p ...

Ordering Operations in Redux

Right now, I'm facing a situation where I need Redux Actions to run one after the other in sequence. I've come across different middlewares like redux-promise that work well if you know the successive actions when triggering the root action. My ...

Dealing with Typescript and React: The Frustration of Property Not Found on Interface, even though it clearly

Dealing with an API where I've linked the properties to an interface using an automated tool: export interface Root { stationId: number; results: Results; } To keep it concise, I'm skipping the additional results interfaces. I then make a fe ...

What is the method for installing particular versions or tags of all npm dependencies?

We are embarking on a complex project that involves the use of numerous node modules and operates within a three-tiered development framework. develop stage production Our goal is to distribute modules to our private registry with tags for develop, stag ...

Converting JSON to PNG format using FabricJS

An image has been created and saved as fabricjs-json. Here is the link to the image: https://i.sstatic.net/7Wrhd.png Below is the json representation of the image: { "version": "5.2.1", "objects": [ { ...

When any part of the page is clicked, the data on the Angular page will automatically

Clicking the mouse anywhere on the page, even in a blank spot, causes the data array to resort itself. I understand that clicking may trigger a view change if an impure pipe is set, but I have not used one. So I am puzzled because my development testing ...

Update the database with the new values and display them in an HTML table

I am working with a table that looks like the one below: <script> $("#edit").hide(); // Initially hide the edit table $("#update").click(function() { $("#edit").toggle(); $("#shown").toggle(); ...

Ways to streamline the organization of Reddit comments?

Looking to avoid using the normalise api for flattening a reddit comment data structure. Here's an example call: https://www.reddit.com/r/reactjs/comments/506gca/what_backend_and_db_are_you_using_with_react/.json This request returns a nested struc ...

Viewing code on Ionic Serve is as quick as a blink of an eye

I am experiencing a strange issue where my code appears for just a moment after running ionic serve and then disappears. I have all the necessary components like nodejs, cordova, ionic, jdk, etc. installed on my machine. As a newcomer to ionic, I would rea ...

Close button for colorbox modal window containing an iframe

I'm currently utilizing colorbox for a modal popup, and the content of the popup is being sourced from a URL. Since it's displayed within an iFrame, I'm wondering how I can incorporate a close button to the modal popup. Thank you The follo ...