Promise of a repeating sequence of serial calls

I am looking to create a recursive serial call to the promise method times, which will return the result of calling the fn function N times and storing the results in an array.

To achieve this, I have added a new attribute called results to the times function to store the output of each invocation of fn.

I want to avoid using module-scoped variables or passing extra parameters like times(fn, n, results) as it would alter the function signature.

Furthermore, I need to find a solution that restricts the use of async/await syntax.

Is there a way to utilize only function-local variables to store the results?

const times = Object.assign(
  (fn: (...args: any) => Promise<any>, n: number = 1) => {
    if (n === 0) return times.results;
    return fn().then((res) => {
      times.results.push(res);
      return times(fn, --n);
    });
  },
  { results: [] as any[] },
);

Usage:

const createPromise = (args: any) =>
  new Promise((resolve) => {
    setTimeout(() => {
      console.log(`[${new Date().toISOString()}]args: `, args);
      resolve(args);
    }, 1000);
  });

async function test() {
  const actual = await times(() => asyncFn('data'), 3);
  console.log(actual);  // output: [ 'data', 'data', 'data' ]
}

Answer №1

Instead of using a stateful result variable, consider reversing the recursion direction:

function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
  if (n === 0) return Promise.resolve([]);
  else return times(fn, n-1).then(results =>
    fn().then(res => {
      results.push(res);
      return results;
    })
  });
}

If you prefer creating promises gradually, you can utilize an accumulator parameter like this:

function times<T>(fn: () => Promise<T>, n: number = 1, results: T[] = []): Promise<T[]> {
  if (n === 0) return Promise.resolve(results);
  else return fn().then(res => {
    results.push(res);
    return times(fn, n-1, results);
  });
}

To avoid adding an optional parameter to your function signature, you can use a local helper function for recursion:

function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
  function recurse(n: number, results: T[]): Promise<T[]> {
    if (n === 0) return Promise.resolve(results);
    else return fn().then(res => {
      results.push(res);
      return recurse(n-1, results);
    });
  }
  return recurse(n, []);
}
// Alternatively, in a more complex and stateful manner:
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
  let results: T[] = [];
  function recurse(): Promise<T[]> {
    if (n-- === 0) return Promise.resolve(results);
    else return fn().then(res => {
      results.push(res);
      return recurse();
    });
  }
  return recurse();
}

Answer №2

If your goal is to create a sequential and recursive pattern, you can achieve it by following these steps:

Unique Solution:

  • Start by creating two promises in your function:
    • finalPromise: This will be the promise returned from the function.
    • promise: A promise that will be created by the passed fn.
  • For finalPromise, make sure to copy the reference of the resolver function and store it for manual invocation, labeled as resolverFn.
  • Create a variable named result to hold values. It should be of type any[].
  • When promise.then is called:
    • Add the received value to the result array.
    • Make a subsequent call to the function.
  • A trick for subsequent calls:
    • If n === 1, the callback passed to times should be resolverFn. Ensure to bind result before passing or use () => resolverFn(result).
    • Otherwise, pass fn.
  • Save the output of this call as innerPromise and when it resolves, invoke resolverFn with the result array.

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

Angular Observable returning null results

After spending some time on this issue, I am still puzzled as to why I am consistently receiving an empty observable. Service: import { Injectable } from '@angular/core'; import { WebApiService } from './web-api-service'; import { Beha ...

Ways to expand the inheritance of a family's assets in the next generation

I am facing an issue with the following code snippet: class Table { get pagination () { return { get item () { return { log (s : string) { console.log(s); ...

Having issues with my JavaScript timer - seeking assistance in troubleshooting the problem

Trying to set a timer for my little game, but facing some difficulties. The timer causes the balance to randomly increase from 0 to 13000 + some extra amount. <script> var coins = 0; var speed = 1; </script> <center> <h4> ...

Transforming Poloniex API Callback JSON into a compatible format for Highcharts.Stockchart

I am currently working on a project that involves retrieving JSON data from Poloniex's public API method (specifically the returnChartData method) to generate a graph using Highchart Stockchart. The graph would display the historical performance of va ...

emphasize area when file is being uploaded

In my "panel-body" section, I have the capability to drop a csv file and input some data into fields. Here is the code in the ejs file: <div class="panel-body"> <div id="fileUpload">click to upload file</div> </div> In the ...

Steps for adding a sound effect, such as a button click noise, when clicking on a div tag

I'm currently working on an app using the Ionic Framework and I need a quick and easy method to play a sound when a div is clicked. Here's what I have so far: <div ng-click="sound()"></div> $scope.sound = function () { //play so ...

Troubleshooting issues with JavaScript progress bar functionality

I have implemented a progress bar using HTML5, JavaScript and Ajax to showcase file uploads in PHP. The issue I am facing is that the progress bar is not displaying the progress correctly. In addition to that, the echo statements in the PHP code are no ...

What is the method for obtaining the value of a React-Select option?

Is it possible to extract the value from the unitOptions array in a React-Select component and then pass it to an Express file for serving as an OpenWeather URL to display weather information? Thank you for your assistance. import React, {useState} from ...

Leveraging partials on their own

I am currently exploring the possibility of loading a partial in linkedin-dustjs without having to load its parent along with it. For instance, consider this partial (login.dust): {>layout/} {<content} <!-- Login Screen --> {/content} Th ...

Problem with UV mapping when adjusting texture size

I am currently working on an application to modify minecraft models. To display the drawn texture mapped on the 3D player model, I am using ThreeJS. However, I'm facing a challenge related to changing the texture size. Initially, the texture is mappe ...

Integrating new components into JSON data

I started by creating a JSON document in my code using the following syntax: let jsonData = []; To populate this document, I utilized the '.push()' method to add elements in this manner: jsonData.push({type: "example", value: "123"}); Eventua ...

What is the best way to convert JavaScript to JSON in Python programming?

I encountered a situation where I have an HTML page that contains a lengthy product list, making it too large for me to upload. The products are stored within the script section of the page, specifically in one variable. Initially, I mistook this data for ...

transferring iterative information via ajax data flow

My form includes hidden input fields that are manually declared in the AJAX data without a loop. How can I efficiently loop through them in the AJAX data? Below is my form script: <form method="POST" name="myform"> <?php for($i=1;$i<=5;$i+ ...

Seeking out a particular key within a JSON object and then finding a match based on the id within that key's array - how can it be

Recently, I've been exploring JavaScript and encountering challenges when trying to apply array methods on objects. For instance, I received a fetch response and my goal is to extract the 'entries' key and then utilize the native Array.find( ...

Change the dropdown header behavior from hovering over it to clicking on it

This snippet of code is integrated into our header to showcase the cart. Currently, the dropdown appears when hovering over it. Is there a way to adjust this so that the dropdown shows up when onclick? <a href="#header-cart" class="skip-link skip-cart ...

Display previous 2 weeks (using vue.js)

Hi, I am using a script in vue.js that currently shows the next 2 weeks, but I need to modify it to display the previous 2 weeks instead. Any suggestions? Thanks. methods: { // Get all days without sunday: dates(index) { var week = new Arra ...

Using JQuery to emphasize selected radio button area

Can someone help me modify the code to highlight the checked radio button by adding or removing a class from the <span class " ui-message ui-state-highlight"> element? Below is the HTML and JS code: $(document).ready(function(){ $('# ...

Bring in a function by its name from the ts-nameof package that is not declared in the d.ts export

Recently, I came across a captivating package that caught my interest and I would love to incorporate it into my TypeScript application: https://github.com/dsherret/ts-nameof However, upon attempting to import the nameof function, I realized it was not be ...

Retrieve data from an ASP.NET Web API endpoint utilizing AngularJS for seamless file extraction

In my project using Angular JS, I have an anchor tag (<a>) that triggers an HTTP request to a WebAPI method. This method returns a file. Now, my goal is to ensure that the file is downloaded to the user's device once the request is successful. ...

Distinguishing which async HTTP GET response is providing data within a callback in Node.JS

I've been diving into the NodeSchool async principles tutorials recently. One particular lesson requires: making asynchronous GET requests to 3 URLs collecting data returned in HTTP responses using callbacks printing the collected data from each res ...