Create a collection of functions within an array that each return promises

I have created 4 different functions that return promises. By running the "hello" function and passing each subsequent function into the next .then, you can generate a single long string output.

var hello = function(str){
  return Promise.resolve(str + "hello")
}
var world = function(str){
  return Promise.resolve(str + "world")
}
var foo = function(str){
  return Promise.resolve(str + "foo")
}
var bar = function(str){
  return Promise.resolve(str + "bar")
}

// hello("alpha").then(world).then(foo).then(bar).then(console.log)
// => alphahelloworldfoobar

My goal is to pass an array of these functions into another function, which will then nest them all together into one final function.

var arr = wrapThen([
  hello,
  world,
  foo,
  bar
])

arr("alpha").then(console.log)

I am wondering if this type of nesting operation is possible, and if Bluebird offers any features for this.

Here is the solution I came up with:

function wrapThen(arr){
  var headPromise = arr.shift()
  return function(){
    var args = _.values(arguments)
    var init = headPromise(args)
    var values = []
    return Promise.each(arr, function(item){
      init = init.then(item)
      return init.then(function(value){
        values.push(value)
        return value
      })
    }).then(function(){
      return _.last(values)
    })
  }
}

Answer №1

Of course, achieving this task is quite simple using bluebird library. By utilizing the reduce method, we can easily aggregate the results:

let result = Promise.reduce([hello, world, foo, bar], function(result, action){
    return action(result);
}, "alpha");

With ES2015 syntax, the code becomes even more concise:

let {reduce} = Promise;
let result = reduce(arr, (result, action) => action(result), "alpha");

var hello = function(str){
  return Promise.resolve(str+ "hello");
};
var world = function(str){
  return Promise.resolve(str+ "world");
};
var foo = function(str){
  return Promise.resolve(str+ "foo");
};
var bar = function(str){
  return Promise.resolve(str+ "bar");
};


Promise.reduce([hello, world, foo, bar], function(result, action){
    return action(result);
}, "alpha").then(function(endResult){ 
    console.log(endResult);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.33/bluebird.min.js"></script>

Answer №2

Unsure whether you want all functions to receive the same parameter alpha or to pass it in sequence, so I have provided solutions for both. By using .reduce and .map, you can achieve this in multiple ways.

var hello = function(str){
  return Promise.resolve(str+ "hello");
};
var world = function(str){
  return Promise.resolve(str+ "world");
};
var foo = function(str){
  return Promise.resolve(str+ "foo");
};
var bar = function(str){
  return Promise.resolve(str+ "bar");
};
 
// Wrap all functions in a list, passing them the same value.
var wrapToArray = function(list) {
  
  return function(result) {
    var allPromises = list.map(function(item) {
      return item(result);
    });
    return Promise.all(allPromises);
  };
  
};

// Wraps all functions, resolving them based on the array's sequence.
var wrapToSequence = function(list) {
  
   return  function(result) {
    // Create a promise that resolves with the result first.
    var promise = Promise.resolve(result);
    // Use reduce to chain the functions.
    promise = list.reduce(function(prev, item) {
      return prev.then(item);
    }, promise);
    return promise;
  };

};

var arr = wrapToArray([hello, world, foo, bar]);
var arr2 = wrapToSequence([hello, world, foo, bar]);

arr("alpha").then(console.log.bind(console));
arr2("alpha").then(console.log.bind(console));
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.33/bluebird.min.js"></script>

Bluebird also provides .reduce, .map to make things easier. To keep the answer concise, a demo is available on jsfiddle.

var wrapToSequence = function(list) {
   return  function(result) {
    return  Promise.reduce(list, function(result, fn) {
      return fn(result);
    }, result);
  };
};

var wrapToArray = function(list) {
  return function(result) {
    return Promise.map(list, function(fn) {
      return fn(result);
    });
  };
};

Answer №3

If you're looking for a way to achieve this task, consider using the Ramda library.

var R = require("ramda")

var greeting1 = function(str){
  return Promise.resolve(str+ "hello")
}
var greeting2 = function(str){
  return Promise.resolve(str+ "world")
}
var action1 = function(str){
  return Promise.resolve(str+ "foo")
}
var action2 = function(str){
  return Promise.resolve(str+ "bar")
}

var finalResult = R.pipeP(greeting1, greeting2, action1, action2)

finalResult("alpha").then(console.log) // outputs -> "alphahelloworldfoobar"

finalResult("alpha") // returns promise -> "alphahelloworldfoobar"

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

What is the best approach to send data to the parent when closing $mdDialog?

When I open a Dialog Window, it has its own controller. Is there a way for me to modify data in the differentController that belongs to the Dialog Window and then send the modified data back to the parent controller when the dialog is being removed? fun ...

What is the best way to retrieve the "name" and "ObjectId" properties from this array of objects? (Using Mongoose and MongoDB)

When trying to access the name property, I encountered an issue where it returned undefined: Category.find() .select("-_id") .select("-__v") .then((categories) => { let creator = req.userId; console.log(categories.name) //unde ...

transform the outcome of a $lookup operation into an object rather than an array

When performing a $lookup from a _id, the result is always 1 document. This means that I would like the result to be an object instead of an array with one item. let query = mongoose.model('Discipline').aggregate([ { $match: { ...

The useEffect function is repeatedly making API calls within a component, despite not having any dependencies specified

As a newcomer to React.Js, I'm encountering an issue with useEffect repeatedly calling an API without any specified Dependency. Is there another approach I should consider? The relevant file is located at: /pages/dashboard/speaking/[slug].js } else i ...

Create a dynamic and interactive website using a combination of jQuery and AngularJS

I recently came across an interesting tidbit on the FAQs of Angular stating that "Angular can use jQuery if it's present in your app when the application is being bootstrapped". This got me thinking, is it considered a best practice to include both j ...

Executing jQuery's $when.apply() function triggers the "then()" method for every individual request that has

Below is a custom jQuery method that I've implemented within an ASP.NET MVC Razor view. The main objective of this function is: Select textAreas Send out an array of ajax requests Display an alert dialog once all ajax requests are completed The cod ...

What is the best way to invoke a TypeScript function within a jQuery function?

Is it possible to invoke a TypeScript function within a jQuery function? If so, what is the correct approach? Here is an example of my component.ts file: getCalendar(){ calendarOptions:Object = { height: 'parent', fixedWeekCount : ...

What sets Express.js apart from koa2.js in handling asynchronous functions?

I've encountered a situation where I had to set up the router using Express, and it was functioning correctly with the following code: router.get('/',(req,res)=>{ queries.getAll().then(stickers=>{ res.json(stickers) }) ...

Choose an image for a better view with the use of HTML and JavaScript/JQuery

Requesting assistance in creating a simple code using plain html5 and JavaScript/jQuery (without plugins) that will enlarge an image upon clicking on it from a list of images. Here is the HTML snippet provided: <!-- Large image holder --> & ...

There was an error parsing the data from the specified URL (http://localhost:8000/src/client/assets/data.json

Hey there, I'm a newcomer to Angular and I'm having trouble reading a JSON array from a file. Every time I try, it gives me a "failed to parse" error. Can someone please provide some guidance? Here is my folder structure: src --assets ---a ...

What could be causing my webpage to freeze every time a filter button is selected?

Tasked with developing a webpage similar to Pinterest by utilizing data from a JSON response. Each JSON object contains a service_name key, which can be manual, twitter, or instagram. I made an effort to implement three filter buttons to only display the r ...

Rearrange Material UI styles in a separate file within a React project

Currently, I am developing an application utilizing material-ui, React, and Typescript. The conventional code for <Grid> looks like this: <Grid container direction="row" justifyContent="center" alignItems="center&q ...

Identify and handle multiple scenarios in JavaScript without using if statements

I have developed a function that is supposed to evaluate all scenarios and provide an immediate result if one of the cases does not match. const addText = (data, addAlternative) => { return (data !== 'N/T' || data === 0 || data) ? d ...

Ensure that Google Tag Manager (GTM) delays the pageview until the SPA URL title is available

I'm dealing with a React SPA that manages all the URL titles on the frontend, so the historyChange event registered on GTM captures the visited URLs along with their titles correctly. However, I've noticed that on the initial load of the SPA, su ...

Can variables be transmitted through Real-Time Communication in JavaScript?

Currently, I am in the process of developing a multiplayer game using three.js. The basic framework is all set up and my next step is to implement the multiplayer aspect. After some research, I came across RTC as a solution that doesn't require comple ...

Exploring Navigation in AngularJS with ui-router

I've encountered an issue with ui-router functionality in my code. Here's a breakdown of the problem: Within my index.html file <li> <a ui-sref="day2">Day 2</a> </li> <li><a ui-sref="day3">Day 3</a& ...

The functionality of the .toggle method is limited to only being effective 1.5

I'm having an issue with making an image popup using the .toggle function in javascript. It seems to work initially, but then only works partially after that. When I click on the image, it opens as expected. However, when I try to close it by clickin ...

How can we prevent users from changing URLs or accessing pages directly in Angular 7 without using authguard?

Hey there! I am trying to find a way to prevent users from accessing different pages by changing the URL, like in this https://i.sstatic.net/E2e3S.png scenario. Is there a method that can redirect the user back to the same page without using Authguard or a ...

VueJS with Vuetify: Issue with draggable cards in a responsive grid

I am currently working on creating a gallery that allows users to rearrange images. To test this functionality, I am using an array of numbers. It is important that the gallery is responsive and displays as a single column on mobile devices. The issue I ...

Using AngularJS to encapsulate an externally loaded asynchronous library as a service

Is there a way to wrap a 3rd party library that loads asynchronously into an Angular service? What is the best practice for incorporating such libraries as services in Angular? Currently, I am approaching it like this: angular.module('myAPIServices ...