Promise all not firing - javascript

I'm trying to get promises work for the first time. However, my Promise.all is never firing.
I'm using node.js & express
const promises = [
new Promise( () => {
var query = `...`;
mssql.query(query, function(obj){
finalRes['key1'] = obj.recordset;
return true;
//this works
});
}),
new Promise( () => {
var query = `...`;
mssql.query(query, function(obj){
finalRes['key2'] = obj.recordset;
return true;
//this works
});
}),
...
]
Promise.all(promises).then(() => {
res.send(finalRes);
// this is never firing
});
I have been googling stuff and I can't find a solution. I would appreciate someone point out what I do wrong here.
Cheers

Your promise creation code is wrong, as they never resolve. What you actually should do is fire resolve functions inside your callback-based code. I'd go a bit further - and make all those promises resolve with their results instead of modifying some external value. Like this:
const promises = [
new Promise( (resolve, reject) => {
var query = `...`;
mssql.query(query, function(obj){
resolve({key1:obj.recordset});
});
}),
new Promise( (resolve, reject) => {
var query = `...`;
mssql.query(query, function(obj){
resolve({key2:obj.recordset});
});
}) // ...
];
Promise.all(promises).then(results => {
res.send(Object.assign({}, ...results));
});
Depending on how queries are built, you might go even further - and write a generic query-generator function, which takes query and key as params, and returns a promise. Again, this function should be easy to test.
As a sidenote, your code is overly optimistic, it should also provide error callbacks with reject() invoke to each query.

Related

Javascript Dynamic Module Import Returns Undefined [duplicate]

I wrote the following node.js file:
var csv = require('csv-parser');
var fs = require('fs')
var Promise = require('bluebird');
var filename = "devices.csv";
var devices;
Promise.all(read_csv_file("devices.csv"), read_csv_file("bugs.csv")).then(function(result) {
console.log(result);
});
function read_csv_file(filename) {
return new Promise(function (resolve, reject) {
var result = []
fs.createReadStream(filename)
.pipe(csv())
.on('data', function (data) {
result.push(data)
}).on('end', function () {
resolve(result);
});
})
}
As you can see, I use Promise.all in order to wait for both operations of reading the csv files. I don't understand why but when I run the code the line 'console.log(result)' is not committed.
My second question is I want that the callback function of Promise.all.then() accepts two different variables, while each one of them is the result of the relevant promise.
First question
Promise.all takes an array of promises
Change:
Promise.all(read_csv_file("devices.csv"), read_csv_file("bugs.csv"))
to (add [] around arguments)
Promise.all([read_csv_file("devices.csv"), read_csv_file("bugs.csv")])
// ---------^-------------------------------------------------------^
Second question
The Promise.all resolves with an array of results for each of the promises you passed into it.
This means you can extract the results into variables like:
Promise.all([read_csv_file("devices.csv"), read_csv_file("bugs.csv")])
.then(function(results) {
var first = results[0]; // contents of the first csv file
var second = results[1]; // contents of the second csv file
});
You can use ES6+ destructuring to further simplify the code:
Promise.all([read_csv_file("devices.csv"), read_csv_file("bugs.csv")])
.then(function([first, second]) {
});
Answer to your second question:
If you want the then callback to accept two different arguemnts, then you can use Bluebird and its spread method. See:
http://bluebirdjs.com/docs/api/spread.html
Instead of .then(function (array) { ... }) and having to access array[0] and array[1] inside of your then handler you will be able to use spread(function (value1, value2) { ... }) and have both variables named as you want.
This is a feature of Bluebird, it's not possible with plain Promise.
You use Bluebird just like Promise, e.g.:
var P = require('bluebird');
// and in your code:
return new P(function (resolve, reject) { ...
// instead of:
return new Promise(function (resolve, reject) { ...
Of course you don't have to name it P but whatever you want.
For more examples see the Bluebird Cheatsheets.

Is it ok to have multiple consumers of 1 promise?

Sample code:
const googleLoadPromise = new Promise(function (resolve, reject) {
google.charts.setOnLoadCallback(function () {
resolve(1);
});
});
googleLoadPromise.then(function () {
// consumer 1 - do something
});
googleLoadPromise.then(function () {
// comsumer 2 - do something else
});
i.e. for the googleLoadPromise, there are two consumers. Is this sort of pattern ok? It seems to work ok - i.e. both consumers get called, and they don't seem to cause problems for each other.
Also, if this is ok, is the order of the running the consumers deterministic (just out of interest, more than anything)?
Yes of course.
You can also just do this if you want to run both functions in sequence:
const googleLoadPromise = new Promise(function (resolve, reject) {
google.charts.setOnLoadCallback(function () {
resolve(1);
});
});
googleLoadPromise
.then(function () {
// consumer 1 - do something
}).then(function () {
// comsumer 2 - do something else
});
Just also remember to handle rejections and catch your promise.
Promises become much easier with async await as well. The below example is more inline with what you wrote:
const googleLoadPromise = new Promise(function (resolve, reject) {
google.charts.setOnLoadCallback(function () {
resolve(1);
});
});
function1 = () => {
// consumer 1 - do something
}
function2 = () => {
// consumer 1 - do something
}
(async function() {
try {
const result = await googleLoadPromise();
function1();
function2();
}
catch( error ) {
console.error( error );
}
}());
Is this sort of pattern ok?
Sure, thats the main usecase of promises.
is the order of the running the consumers deterministic (just out of interest, more than anything)?
Yes, the callback attached first with then gets executed first, however I wouldnt rely on it. If you want to run one callback after another, chain them accordingly.
// ok:
promise
.then(first);
promise
.then(second);
// better if second depends on first:
promise
.then(first)
.then(second);

how to convert callback to promise

I'm trying to learn about what the promise is and how to convert callback to promise. While I'm converting my code to promise I got very confused about the ref. I would very appreciate it if you show me how to convert this code as a simple example.
database.ref('/users').on("child_added").then(function(snap){
var subData = snap.val();
database.ref('/subs/' + subData.subid + '/pri/' + snap.key).once("value").then(function(userSnap) {
var userData = userSnap.val();
subData.name = userData.name;
subData.age = userData.age;
database.ref('/subs/' + subData.subid).once("value",function(subDSnap) {
var subDData = subDSnap.val();
subData.type = subDData.type;
database_m.ref('/users/' + snap.key).set(subData);
});
});
});
A Promise is not a replacement for every type of callback; rather it's an abstraction around one particular task that will either succeed once or fail once. The code you're converting looks more like an EventEmitter, where an event can occur multiple times, so replacing .on('child_added', ...) with a Promise implementation is not a good fit.
However, later on, you have a .once(...) call. That's a bit closer to a Promise in that it will only complete once. So if you really wanted to convert that, here's what it could look like:
function get(database, url) {
return new Promise(function (resolve, reject) {
database
.ref(url)
.once('value', resolve)
.once('error', reject);
});
}
database.ref('/users').on("child_added", function(snap) {
var subData = snap.val();
get(database, '/subs/' + subData.subid + '/pri/' + snap.key)
.then(function(userSnap) {
var userData = userSnap.val();
subData.name = userData.name;
subData.age = userData.age;
return get(database, '/subs/' + subData.subid);
})
.then(function(subDSnap) {
var subDData = subDSnap.val();
subData.type = subDData.type;
database_m.ref('/users/' + snap.key).set(subData);
})
.catch(function (err) {
// handle errors
});
});
});
I am not sure I understand the question and if your "on" is returning a promise or just listening, but in your code you have nested '.then', which is not the common way to deal with promises and I am not sure that's what you wanted to achieve here.
You could do (assuming that the on function returns a promise, which I doubt)
database.ref('/users').on("child_added")
.then(function(snap){/* do something with the first part of your snap function*/})
.then (results => {/* do something else, such as your second ref call*/})
.catch(error => {/* manage the error*/})
To learn about promises, there are many examples online but what I really liked is the promise tutorial at google, with this nice snippet that explains it
var promise = new Promise(function(resolve, reject) {
// do a thing, possibly async, then…
if (/* everything turned out fine */) {
resolve("Stuff worked!");
}
else {
reject(Error("It broke"));
}
});
then, once you have the function that returns this promise, you can start doing
.then(...)
.then(...)
.then(...)
.catch(...)

Using Promises to call function inside another function with Bluebird promises library

I have 3 Node Js functions. What I'm trying to do here is, I want to call normalizeFilePath and get the normalized path, after that check whether a file exist or not with that normalizedFilePath and after all these, create a file if the file doesn't already exist. This is the first day of using promises (Bluebird) and I'm new to Node JS and Java Script. Below code structure is getting complex. Of course this is not a good idea at all.
var createProjectFolder = function (projectName) {
};
var checkFileExistance = function (filePath) {
return new promise(function (resolve, reject) {
normalizeFilePath(filePath).then(function (normalizedFilePath) {
return fs.existSync(normalizedFilePath);
});
})
};
var normalizeFilePath = function (filePath) {
return new promise(function (resolve, reject) {
resolve(path.normalize(filePath));
});
};
How can i manage promises to implement that concept?
Let's improve your code in two simple steps.
Promises are meant for async functions
As long as path.normalize is synchronous, it should not be wrapped in promise.
So it can be as simple as that.
var normalizeFilePath = function (filePath) {
return path.normalize(filePath);
};
But for now lets pretend that path.normalize is async, so we can use your version.
var normalizeFilePath = function (filePath) {
return new Promise(function (resolve, reject) {
resolve( path.normalize(filePath) );
});
};
Promisify all the things
Sync is bad. Sync blocks event loop. So, instead of fs.existsSync we will use fs.exists.
var checkFileExistance = function (filePath) {
return new Promise(function (resolve, reject) {
fs.exists(filePath, function (exists) {
resolve(exists);
});
});
};
As You can see, we are wrapping async function that accepts a callback with a promise. It's quite a common concept to "promisify" a function, so we could use a library for that. Or even use fs-promise, that is -- you guess it -- fs with promises.
Chaining promises
Now, what we want is making three actions one after another:
Normalize file path
Check if file already exists
If not, create a directory
Keeping that in mind, our main function can look like this.
var createProjectFolder = function (projectName) {
normalizeFilePath(projectName)
.then(checkFileExistance)
.then(function (exists) {
if (!exists) {
// create folder
}
})
.catch(function (error) {
// if there are any errors in promise chain
// we can catch them in one place, yay!
});
};
Don't forget to add the catch call so you would not miss any errors.

Chaining promises with RxJS

I'm new to RxJS and FRP in general. I had the idea of converting an existing promise chain in my ExpressJS application to be an observable for practice. I am aware that this probably isn't the best example but maybe someone can help shed some light.
What I'm trying to do:
I have two promises - prom1 and prom2
I want prom1 to run before prom2
If prom1 sends a reject(err), I want to cancel prom2 before it starts.
I want the error message prom1 returns to be available to the onError method on the observer.
var prom1 = new Promise(function(resolve, reject) {
if (true) {
reject('reason');
}
resolve(true);
});
var prom2 = new Promise(function(resolve, reject) {
resolve(true);
});
// What do I do here? This is what I've tried so far...
var source1 = Rx.Observable.fromPromise(prom1);
var source2 = source1.flatMap(Rx.Observable.fromPromise(prom2));
var subscription = source2.subscribe(
function (result) { console.log('Next: ' + result); },
// I want my error 'reason' to be made available here
function (err) { console.log('Error: ' + err); },
function () { console.log('Completed'); });
If I understood what you are trying to do - you need to create two deferred observables from functions that return promises and concat them:
var shouldFail = false;
function action1() {
return new Promise(function (resolve, reject) {
console.log('start action1');
if (shouldFail) {
reject('reason');
}
resolve(true);
});
}
function action2() {
return new Promise(function (resolve, reject) {
console.log('start action2');
resolve(true);
});
}
var source1 = Rx.Observable.defer(action1);
var source2 = Rx.Observable.defer(action2);
var combination = Rx.Observable.concat(source1, source2);
var logObserver = Rx.Observer.create(
function (result) {
console.log('Next: ' + result);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
then for normal case:
combination.subscribe(logObserver);
// start action1
// Next: true
// start action2
// Next: true
// Completed
And case where fisrt promise fails:
shouldFail = true;
combination.subscribe(logObserver);
// start action1
// Error: reason
http://jsfiddle.net/cL37tgva/
flatMap turns an Observable of Observables into an Observable. It's used in many examples with Promises because often you have an observable and in the map function you want to create a promise for each "item" the observable emmits. Because every fromPromise call creates a new Observable, that makes it an "observable of observables". flatMap reduces that to a "flat" observable.
In your example you do something different, you turn a single promise into an observable and want to chain it with another observable (also created form a single promise). Concat does what you are looking for, it chains two observables together.
The error case will work as you would expect.
Observable.forkJoin works great here receiving array of other Observables.
Rx.Observable.forkJoin([this.http.get('http://jsonplaceholder.typicode.com/posts'), this.http.get('http://jsonplaceholder.typicode.com/albums')]).subscribe((data) => {
console.log(data);
});

Categories

Resources