Put Javascript Promise into Functions - javascript

I have two promises that I am resolving with promise.all:
var mictest1 = new Promise((resolve, reject) => {
resolve(true);
});
var mictest2 = new Promise((resolve, reject) => {
resolve(true);
});
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
I would like to put the promises mictest1 and mictest2 into a function called mictest() so it does the following:
mictest();
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
In this way I can call the function at will, and when the promises get complicated, i don't have that block of text in front of promise.all

Maybe you're looking for the mictest function to return the Promise.all?
const mictest = () => {
var mictest1 = new Promise((resolve, reject) => {
resolve(true);
});
var mictest2 = new Promise((resolve, reject) => {
resolve(true);
});
return Promise.all([mictest1, mictest2]);
};
mictest().then((data) => {
console.log('test passed:', data);
});

I think you are looking for a function that returns the promise:
function mictest() {
return new Promise((resolve, reject) => {
resolve(true);
});
}
You'd use it like
var mictest1 = mictest();
var mictest2 = mictest();
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
or simply
Promise.all([mictest(), mictest()]).then(data => {
console.log("test passed: " + data);
})

Not quite the way you imagined it but you can get very close:
let promises = mictest();
Promise.all(promises).then(data => {
console.log("test passed: " + data);
})
That's just changing two lines of your imagined code. The implementation is simple:
function mictest () {
return [
new Promise((resolve, reject) => {
resolve(true);
}),
new Promise((resolve, reject) => {
resolve(true);
})
]
}
A promise is a value just like strings, numbers, arrays etc. You can treat it like any value. It just happens to be an object that has a .then() method and is awaitable
Note: actually, any object with a .then() method is awaitable even your own custom created non-promise object (actually any object with a .then() method is a promise even though it is not a Promise)

Related

Programmatically add arguments to a Promise

I need to create a function that receives a Promise as a first parameter and an array of its parameters (if it has at least one) or null if none.
My function looks this way:
var executeMappingStep = (promiseStatus, myPromise, myPromiseParams) => {
return new Promise((resolve, reject) => {
//if the execution was success, there's no need to invoke myPromise again
if(promiseStatus.success == true)
return resolve(promiseStatus.previousResponseSaved);
if (myPromiseParams!= null) {
//how I resolve this logic is my doubt
myPromise.addArrayOfParameters(myPromiseParams);
}
myPromise().then(result => resolve(result)).catch(err => reject(err));
});
};
I was reading about the .bind() function which works for functions but not for promises according to this question. I also saw something about the .apply() function, but this doesn't seems to be what I need.
Edit
My function is invoked like myFirstPromise when there aren't parameters, and like mySecondPromise when I have at least one:
var executePromises = (myFirstPromise, mySecondPromisePromise) => {
return new Promise((resolve, reject) => {
//retrieve an array of every promise status
var promisesStatus = getPromisesStatus();
executeMappingStep(promisesStatus[0], myFirstPromise, null).then(result => {
return convertToXml(result);
}).then(result => {
var parameters = {
value1 : result,
value2: [1,2,3],
value3: "some string",
value4: 10
};
return executeMappingStep(promisesStatus[1], mySecondPromisePromise, parameters);
}).then(result => resolve(result)).catch(err => reject(err));
});
};
var myFirstPromise = function() {
return new Promise(function (resolve, reject) {
//some logic for first promise
});
}
var mySecondPromise = function(firstParam, secondParam, thirdParam, fourthParam) {
return new Promise(function (resolve, reject) {
//some logic for second promise with its params
});
}
Probably, in the function addArrayOfParameters I need to loop into every property on the object (I realized that an array would not work), like this
Is there a way to programmatically add parameters from an array before its resolved?
Edit 2
The reason behind this logic is much complex, but this is pretty much what I need to solve. Basically, in my code, every promise can be executed with errors and there's a logic involved in the executePromises function which returns the status of every promise whether was successfully executed or not. This logic involves more than 10 promises chained, and if some of them fail e.g: promise number 5, then 6,7 etc, will have to be invoked again in some admin backend.
I don't what to replicate the logic for each promise, so that's why I wanted to create the executeMappingStep function to encapsulate that logic.
Probably is hard to explain, I tried to simplify the most as I could. I made a few more changes to explain what I just said.
Probably, I have complicated things a lot here, but anyway, this is the solution that I wanted.
It's good to know that the .then function can invoked in other place and the promises can be created with the needed arguments and then sent as parameter.
With that said:
var executePromises = (myFirstPromise, mySecondPromisePromise) => {
return new Promise((resolve, reject) => {
//retrieve an array of every promise status
var promisesStatus = getPromisesStatus();
executeMappingStep(promisesStatus[0], myFirstPromise()).then(result => {
return convertToXml(result);
}).then(result => {
var mySecondPromisePromiseParameter = mySecondPromise(result, [1,2,3], "some string", 10);
return executeMappingStep(promisesStatus[1], mySecondPromisePromiseParameter);
}).then(result => resolve(result)).catch(err => reject(err));
});
};
An then, the executeMappingStep just receives the promise and invokes the .then internally, this way:
var executeMappingStep = (promiseStatus, myPromise) => {
return new Promise((resolve, reject) => {
//if the execution was success, there's no need to invoke myPromise again
if(promiseStatus.success == true)
return resolve(promiseStatus.previousResponseSaved);
myPromise.then(result => resolve(result)).catch(err => reject(err));
});
};
Probably use async library may resolve your issue. Try to run code on your console and look into that.
With async library:
var async = require("async");
async.waterfall([
function (callback) {
var methodParam = [1, 2, 3];
console.log("first method called");
callback(null, methodParam);
},
function (methodParams, callback) {
var newParams = [4, 5, 6];
newParams = methodParams.concat(newParams);
console.log("second method called", methodParams);
callback(null, newParams);
}
], function (err, res) {
if (err) {
console.log("error occured");
} else {
console.log("final result", res);
}
});
With promise:
var promise1 = (() => {
return new Promise((resolve, reject) => {
var methodParam = [1, 2, 3];
console.log("first promise called");
resolve(methodParam);
});
});
var promise2 = ((methodParams) => {
return new Promise((resolve, reject) => {
var newParams = [4, 5, 6];
newParams = methodParams.concat(newParams);
console.log("second promise called", methodParams);
resolve(newParams);
});
});
promise1()
.then((resPromise1) => {
return promise2(resPromise1);
}).then((resPromise2) => {
console.log("final result", resPromise2);
});

Nested Promises, And Another After Completion [duplicate]

I have a situation where I think the only choice for me is to nest some Promises within each other. I have a Promise that needs to be performed and a method that does something until that Promise is complete. Something like this:
let promise = new Promise((resolve, reject) => {
// Do some stuff
});
doSomethingUntilPromiseisDone(promise);
However, within my Promise, I need to execute another method that returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
// Do something here
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
But now, in the fetchValue method's then statement, I have another method I need to execute that, guess what, returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
saveToCache(value)
.then((success) => {
console.log('success!!');
resolve('success');
});
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
So in the end, I have a Promise, within a Promise, within a Promise. Is there someway I can structure this better so that it is more straightforward? It seems like nesting them within each other is counter to Promise's intended chaining approach.
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
you can use generator to flatten your nested promises (Bluebird.couroutine or Generators)
//Bluebird.couroutine
const generator = Promise.coroutine(function*() {
try {
const value = yield fetchValue(url);
const success = yield saveToCache(value);
console.log('success:', success);
} catch(e) {
console.error(err);
}
}));
generator();
Each function will call the next one with the result of the method before.
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);

JavaScript Promise wrapped in function or bare?

If I'm calling a function that is a promise, do I need to do this "wrap it in another function" layer?
Promise
.resolve()
.then(()=>{ // this part seems excessive
return new Promise(resolve={
// my function's guts
Can I return the new promise directly, like
Promise
.resolve()
.then(new Promise(resolve={
// my function's guts
If I'm calling a function that is a promise, do I need to do this
"wrap it in another function" layer?
Yes otherwise it'll be executed immediately I recommend you create your promises within a named function that way it allows you to keep your chain neat and readable and code more reusable.
myTask1()
.then(myTask2)
.then(myTask3);
function myTask1() {
return new Promise((resolve, reject) => {
console.log("Task 1");
resolve("Task 1");
})
}
function myTask2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Task 2");
resolve("Task 2");
}, 1000)
})
}
function myTask3() {
return new Promise((resolve, reject) => {
console.log("Task 3");
resolve("Task 3");
})
}
Can I return the new promise directly, like.... .then(new Promise(resolve={?
No there's one critical difference with instantiating the promise like that. When you wrap the promise in a function it isn't evaluated until the previous promise completes whereas if you instantiate it inline then it's evaluated immediately which may cause unexpected results:
new Promise((resolve, reject) => {
resolve()
})
.then(new Promise((resolve, reject) => {
console.log("Task 1");
}))
.then(new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Task 2");
resolve("Task 2");
}, 1000);
}))
.then(new Promise((resolve, reject) => {
console.log("Task 3");
resolve("Task 3");
}))
To make the above work you could change it so that the closure returns a promise, but it starts to look pretty messy:
new Promise((resolve, reject) => {
resolve()
})
.then(() => {
return new Promise((resolve, reject) => {
console.log("Task 1");
resolve("Task 1");
})
})
.then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Task 2");
resolve("Task 2");
}, 1000);
});
})
.then(() => {
return new Promise((resolve, reject) => {
console.log("Task 3");
resolve("Task 3");
});
})
You do have to wrap the promise in another function.
However, you can shorten it a bit because:
() => {
return new Promise()
}
is the same as
() => new Promise()
So you could do something like this:
Promise
.resolve()
.then(() => new Promise(resolve => {
// your function's guts
There is no need to use Promise.resolve() when creating a new promise.
The usual way to create a promise is to make a function that returns the promise:
function myFunc() {
return new Promise((resolve, reject) => {
// your async logic here
});
}
Then, you call it like this:
myFunc().then(result => {
// code that uses async result here
});
And, you have put your promise creation logic into a reusable function.
It is possible (though usually less practical) to create a new promise without putting it in a containing function. For example, you can do this:
new Promise((resolve, reject) => {
// async logic here that eventually calls resolve or reject
}).then(result => {
// process async result here
}).catch(err => {
// process error here
});
The handler for then could simply return a value.
Promise.resolve('value').then(() => 'otherValue');

Promise.then() but functions run async

I'm new to Javascript and doing a crawler, I've created 4 Promise as these
var openConfig = new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) throw err;
config = JSON.parse(data);
client = new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
resolve();
})
})
var openFile = new Promise((resolve, reject) => {
console.log('Opening file...')
fs.readFile('./writing/writing.json', (err, data) => {
if (err) throw err;
writing = JSON.parse(data);
console.log('Done parsing file');
resolve();
})
})
var ask = new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('Which lesson do you want to add? ', (ans) => {
lessonId = ans;
rl.close();
resolve();
})
})
var createLesson = new Promise((resolve, reject) => {
console.log('Now processing lesson ' + lessonId);
})
then call the first Promise
openConfig
.then(() => {
return openFile;
})
.then(() => {
return ask;
})
.then(() => {
return createLesson;
})
but as I run, the console show
Opening file...
Which lesson do you want to add? Now processing lesson undefined
Done parsing file
which I understood as my promises are wrong and my function run async. Can you help me to fix this?
Thank you.
Promises are not "called". In your then chain, you only sequentially await them - but the tasks were already started when you created the promises. If you want to sequence the actions, put them in functions.
Btw, your code contains multiple typical mistakes. Don't use global variables, and always promisify at the lowest possible level:
function openFile(path) {
return new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) reject(err); // never `throw err` in non-promise callbacks!
else resolve(data);
});
});
}
function openJSON(path) {
return openFile(path).then(JSON.parse);
}
function openConfig(path) {
return openJSON(path).then(config =>
new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
)
}
function ask(question) {
return new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question(question, ans => {
rl.close();
resolve(ans); // always resolve to *something*
});
});
}
readConfig('./config.json')
.then(client => {
console.log('Opening file...')
return openJSON('./writing/writing.json');
})
.then(writing => {
console.log('Done parsing file');
return ask('Which lesson do you want to add? ');
})
.then(lessonId => {
console.log('Now processing lesson ' + lessonId);
});
Instead of assigning new Promises to vars (these run as soon as created), you should wrap them into functions, which in turn return a new Promise
To help you understand here's a simplified example:
function p1 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {a:1}));
});
}
function p2 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {b:2}));
});
}
function p3 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {c:3}));
});
}
p1({z:0})
.then(p2)
.then(p3)
.then((data)=>console.log(data))
This results in { z: 0, a: 1, b: 2, c: 3 }
See here if you wish to experiment a bit with the above: https://repl.it/DwNB/0
On a separate note, if you are using promises, you should also handle errors in the chain in a final .catch() instead of synchronously throwing midway. That's what the reject callback is for!

Look for Promise bluebird code review for node.js

When and where need to use new Promise(Function<Function resolve, Function reject> resolver) -> Promise
My Sample code:
userInfo.js
var Promise = require('bluebird');
var winston = require('winston');
var _ = require('lodash');
var request = Promise.promisify(require("request"));
exports.getWeather = function (data) {
var cityName = data.userProfile.city;
return request("http://0.0.0.0:3003/api/Weather/byCity?city=" + cityName).spread(function (res, body) {
var result = JSON.parse(body).data;
return _.merge(data, result);
});
};
exports.getUserProfile = function (userId) {
return new Promise(function (resolve, reject) {
request("http://0.0.0.0:3003/api/UserProfile/getUserProfile?id=" + userId).spread(function (res, body) {
var result = JSON.parse(body).data;
resolve(result);
});
})
};
exports.getEvents = function (data) {
var cityName = data.userProfile.city;
return request("http://0.0.0.0:3003/api/Events/byCity?city=" + cityName).spread(function (res, body) {
var result = JSON.parse(body).data;
return _.merge(data, result);
});
};
exports.getFashion = function (data) {
var gender = data.userProfile.gender;
return request("http://0.0.0.0:3003/api/Fashion/byGender?gender=" + gender).spread(function (res, body) {
var result = JSON.parse(body).data;
return _.merge(data, result);
});
};
exports.displayDetail = function (data) {
console.log(data);
};
Above code I try call in 2 way in promise
getUserProfile.js
var userInfo = require('./userInfo');
module.exports = function(){
return userInfo.getUserProfile(3)
.then(userInfo.getFashion)
.then(userInfo.getEvents)
.then(userInfo.getWeather)
.then(userInfo.displayDetail)
.catch(function (e) {
console.log('Error:');
console.error(e.stack)
})
.finally(function () {
console.log('done');
});
}
2nd way:
getUserInformation.js
var userInfo = require('./userInfo');
module.exports = function () {
return new Promise(function (resolve, reject) {
resolve(3);
})
.then(userInfo.getUserProfile)
.then(userInfo.getFashion)
.then(userInfo.getEvents)
.then(userInfo.getWeather)
.then(userInfo.displayDetail)
.catch(function (e) {
console.log('Error:');
console.error(e.stack)
})
.finally(function () {
console.log('done');
});
};
getDetails.js
var userInfo = require('./getUserInformation');
userInfo()
.then(function(){
console.log('getDetails done')
})
.catch(function (e) {
console.log('Error:');
console.error(e.stack)
})
.finally(function () {
console.log('done');
});
please let me know what the difference and is there any issues by using these way?
exports.getUserProfile = function (userId) {
return new Promise(function (resolve, reject) {
request("http://0.0.0.0:3003/api/UserProfile/getUserProfile?id=" + userId).spread(function (res, body) {
var result = JSON.parse(body).data;
resolve(result);
});
})
};
Please don't do this. Just return from the callback, and return the promise created by then, like you have done it in your other three methods.
return userInfo.getUserProfile(3)
.then(…)
vs.
return new Promise(function (resolve, reject) {
resolve(3);
})
.then(userInfo.getUserProfile)
.then(…)
Well, the first one is much more readable and concise. They're pretty much equivalent except for the case that getUserProfile does throw synchronously, which it shouldn't anyway. Also in the first case getUserProfile is invoked as a method on userInfo, while in the second case it's just a callback function, the this in the calls will be different.
The second pattern can be tremendously simplified though by using Promise.resolve instead of the new Promise constructor:
return Promise.resolve(3)
.then(userInfo.getUserProfile)
.then(…)
This is totally fine, and aligns better with the rest of the chain. Speaking of which, …
.then(userInfo.getFashion)
.then(userInfo.getEvents)
.then(userInfo.getWeather)
where each of the functions returns a promise that resolves with
additional data merged into its argument
is not exactly the best way to solve this. Yes, it ensures that these three functions are called after each other, and is an acceptable pattern for that case. However, in your case you're mixing the request calls to the API with that argument-extraction and result-merging in the same function; which by the separation of concerns you shouldn't. Rather make the functions pure
exports.… = function (arg) {
return request("http://0.0.0.0:3003/api/…?…=" + arg).spread(function (res, body) {
return JSON.parse(body).data;
});
};
And now you can combine them separately - and not only in sequence, but also in parallel:
userInfo.getUserProfile(3)
.then(function(data) {
var p = data.userProfile;
return Promise.prop({
userProfile: 0,
fashion: userInfo.getFashion(p.gender), // `\
events: userInfo.getEvents(p.city), // }=> execute requests in parallel
weather: userInfo.getWeather(p.city) // ./
});
})
.then(userInfo.displayDetail)
.catch(function (e) {
console.error('Error:', e.stack)
});
The first way is much more readable, and there's no benefit to starting the chain with a promise that returns a constant as in your second way.
They both do effectively the same thing, with one caveat: In your second example (Starting the chain with a Promise), the getUserProfile call will be run on the next tick (Similar to if you'd thrown it in a setTimeout 0) rather than atomically.

Categories

Resources