promisifyAll in bluebird.js - javascript

I am trying to understand how promisifyAll works. i am trying hard to understand the example given in their documentation. Can anyone please give me a simple example, how it works? I am trying to understand the concept and how we can use it. Thank you
var objects = {};
objects.first = function(){
console.log("First one is executed");
}
objects.second = function(){
console.log("second one is executed");
}
objects.third = function(){
console.log("third one is executed");
}
how can we promisify the objects variable? or something like that.

First, you need to understand how a nodeFunction works. It takes a callback function as the last argument. This callback takes two arguments, the first one is error and the second the data. Consider for example require("fs").readFile:
// This is the callback
function callback (error, data) {
if (error) {
console.error('There was an error', error)
} else {
console.log('This is the data', data)
}
}
require('fs').readFile('my-file.txt', callback)
Note that this is a convention, there's nothing in JS itself that enforces it.
Let's move to Promise.promisify now. This method takes a nodeFunction and returns a promisified version of it. This is more or less what it does:
function promisifiedReadFile (filePath) {
return new Promise(function (fulfill, reject) {
require('fs').readFile(path, function (error, data) {
if (error) { reject(error) } else { fulfill(data) }
})
})
}
It's a bit verbose but as you can see you now have a version of readFile that returns a promise instead of accepting a callback. Of course, this example is hard-coded for readFile, Promise.promisify works for any nodeFunction instead:
const promisifiedReadFile = Promise.promisify(require('fs').readFile)
The two promisifiedReadFile methods work in the same way.
Last, Promise.promisifyAll takes an object, goes through it and finds all the methods, it then applies Promise.promisify to each of them.
So, if you call Promise.promisifyAll(require('fs')) you get back a version of the fs module where all the methods return promises instead of accepting callbacks.
About your example I'm not sure what you're trying to achieve but the methods you defined are not nodeFunctions so they can't be promisified.

Related

Understanding setTimeout and its implementation in JavaScript Promises

I have the following code:
function MyPromise(configFunction) {
let nextSuccessCallBack = undefined;
let nextResolve = undefined;
configFunction(function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
});
return {
then: function(successCallback) {
nextSuccessCallBack = successCallback;
return new MyPromise(function(resolve) {
nextResolve = resolve;
})
}
}
}
new MyPromise(function(resolve, reject) {
resolve('new message');
}).then(function(message) {
console.log(message);
return 'another message'
}).then(function(message) {
console.log(message)
console.log('here')
})
In this example, it seems that the nextSuccessCallBack is set to be the callback functions within .then, then its value within the setTimeout function is now populated. However, this confuses me. I thought that when we reach the return statement in the constructor, we return the object and effectively stop the function? If that the case then how does the program even get to the setTimeout?
This is not a correct Promise implementation. It clearly has no capabilities for rejections, but also for the implemented fulfilment feature it does not comply with the Promises/A+ specification. Just to give two examples:
It does not comply with rule 2.1.2.2
When fulfilled, a promise must have a value, which must not change.
....nor with rule 2.2.2.3:
If onFulfilled is a function it must not be called more than once.
In your implementation, if you would add a second call to resolve:
new MyPromise(function(resolve, reject) {
resolve('new message'); resolve('new message2');
}).then((function(message) {
console.log(message);
// ... etc
})
...then both calls to resolve would fire the then callback, and show that the promised value was modified after the first time it was set. This is in complete violation of the principle of promises: promises can only resolve once.
It does not comply with rule 2.2.6:
then may be called multiple times on the same promise.
If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
This does not happen if we use the following code:
let p = new MyPromise(resolve => resolve("value"));
p.then(console.log); // This callback is called
p.then(console.log); // This callback is not called -> violation!
These are basic shortcomings, and this is just the tip of the iceberg.
If you are interested in how it could be implemented in compliance with Promise/A+, then have a look at one I did a few years ago with a step-by-step explanation.
As to your question
how does the program even get to the setTimeout?
When your main code executes this:
new MyPromise(function(resolve, reject) {
resolve('new message');
})
...then the parameter variable configFunction is initialised with that callback function. The MyPromise constructor calls it, passing it the following callback as first argument:
function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
}
So that means that resolve in your main code's callback function is initialised with the above callback function. Then your main code's callback function calls resolve with a string argument. Since resolve is the above callback function, we can see it gets executed with message initialised to "new message". This function executes setTimeout.
The code in the snippet does solve the purpose but, it is confusing as is a bad implementation of a Promise according to the way MDN Uses Promises in JavaScript for better code efficiency and understanding.
The above code can also be written this way:
const examplePromise = new Promise((resolve, reject) => {
resolve("Another Message");
});
console.log("New Message");
examplePromise.then((message) => {
console.log(message);
});
Now, for better understading of the concept of Promises in JavaScript, I'll take another example:
Let's say I want to create a program which says hello and then after 2 seconds says How Are You?
There are two ways of solving this
Just using the setTimeout() function which executes a function after certain period of time
Using promises with setTimeout()
Case I (Using setTimeout()):
console.log("hello"); //Saying hello for the first time
setTimeout(function () {
console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds
Case II (Using Promises)
console.log("hello");
const example = new Promise((resolve) => {
setTimeout(() => {
resolve("How Are You?");
}, 2000);
});
example.then((message) => {
console.log(message);
});
Now, for simple cases like logging a message after 2 seconds do not require Promises. You may use them (No problem) but actually, Promises are used in cases where, you wait for a function to execute a Database Query or you need to wait for a server to give you some HTML Response or while using WebAPIs, etc.
P.S: setTimeout() is just an example. It is not a rule that you always have to use setTimeout() while writing a Promise. If you are fetching data using a WebAPI, you usually write $.ajax(...).then(...) or fetch(...).then(...) instead of setTimeout()

Function with call to FireStore always returns undefined

I am trying to implement a function to check if a doc exists in my FireStore database, given an id. The problem is my fire_PatronExists function always return undefined.
const patronsRef = db.collection("patrons");
alert(fire_PatronExists(user.uid));
function fire_PatronExists(id) {
patronsRef.doc(id).get().then(function(doc) {
// return doc.exists();
if (doc){return true}else {return false}
}).catch(function(error) {
console.log("Error getting document:", error);
});
}
The fact that your function returns undefined is totally normal: get() is an asynchronous method, so the return you put inside the then will not be executed inside fire_PatronExists; it will be executed a bit later. There is a great SO article that explains the difference between synchronous and asynchronous execution.
There are different solutions, depending on the version of JavaScript you are using. One that will work for sure is passing a callback function to fire_PatronExists and pass the result to that function.
This would look like that (not tested):
const patronsRef = db.collection("patrons");
fire_PatronExists(user.uid, function(exists) {
alert(exists);
});
// Remember though, if you put code here, it will be executed in parallel
// with the code you put inside your callback.
function fire_PatronExists(id, callback) {
patronsRef.doc(id).get().then(function(doc) {
}).catch(function(error) {
console.log("Error getting document:", error);
});
}
Using callbacks can get really messy though. If you are using a recent version of JavaScript, you might want to read about the async and await keywords, they can improve your code readability a lot.

Promises in series

I have problem running multiple premises in series, using Q and reduce idiom (see: http://taoofcode.net/promise-anti-patterns/)
I tried to follow this example, change it a little bit and here's what I've got:
playlist.createPlaylist('playlist')
.then(function(playlistId) {
songsInfo.reduce(function (accumulatedPremise, songInfo) {
accumulatedPremise.then(function (response) {
var def = Q.defer();
youtube.search(songInfo, function (songInfo, resp) {
var song = songParser.parse(songInfo, resp);
if (song !== null) {
playlist.addSongToPlaylist(song, playlistId).then(function(response) {
def.resolve(response)
})
}
});
return def.promise;
})}, Q());
});
Now, I should probably talk a little about main idea behind this:
1) I'm creating a youtube playlist. From createPlaylist function, I'm returning a promise with playlist's ID and then
2) for each SongInfo I have I need to invoke search method on my youtube module. Search function also takes a callback. In this case, I'm invoking addSongToPlaylistMethod if desired song was found/parsed correctly. As you can see, addSongToPlaylist also returns a Promise.
Now, the problem:
all the block inside
then
method, invoked on
accumulatedPremise
is executed only once.
You could probably ask me why simply not to use forEach in this case? Well, because of
http://www.acnenomor.com/3037813p1/playlistitems-batch-insert-youtube-api-v3
Could you please help me fixing it?
Cheers,
Slawek
You're not returning anything from the reduce function.
accumulatedPremise.then(function (response) {
should be:
return accumulatedPremise.then(function (response) {

Stringing together an unknown number of callbacks to be executed one after another

I have a phonegap application and I want it to upload multiple files to a server which is an async operation. However, because of bandwidth concerns I want to upload the files sequentially and alert the user to the progress.
However, I'm a bit stuck. Since the api is non-blocking and I am (somewhat) attempting to block, I'm not sure exactly how to do this.
I need to do something like this:
files[0].upload().done = function() {
files[1].upload().done = function() {
files[2].upload().done = function() {
files[3].....files[n]
}
}
}
How can I do this? At this time, I don't care about failed uploads.
In JavaScript you can define a function that returns a function.
function get_callback(index){
return function(){
// TODO: check if files[index] exists
files[index].upload().done = get_callback(index+1);
}
}
files[0].upload().done = get_callback(1);
You could use a Promises/Futures library, such as FuturesJS and one of its components, Sequence.
The sequence module allows one to chain asynchronous functions through callbacks. You first need to create the sequence, then append as many callbacks as you need. Every callback to the sequence object receives at least two arguments, next and err. You need to call next when the asynchronous function ends.
Something like this should work:
var Sequence = require('sequence').Sequence,
sequence = Sequence.create();
sequence
.then(function (next, err) {
if (err) {...}
files[1].upload(next);
})
.then(function (next, err) {
if (err) {...}
files[2].upload(next);
})
.then(...)
.then(function (next, err) {
console.log('all files uploaded');
});
Your upload function must receive a callback in order to the code above to work. If it doesn't, just change it in the following way:
var upload = function (callback) {
//the rest of your code
//at the very end
callback();
}

Join thread in JavaScript

Probably asked before, but after the serious searching I'm still not able to find a proper solution. Please consider something like this:
function compute() {
asyncCall(args, function(err, result) {
});
/* 'join thread here' */
}
Even though asyncCall is asynchronous I'd like to use the result and return it from the function compute synchronously. asyncCall is a library call and I can't modify it in any way.
How to wait properly for the asynchronous result without setTimeout and watching a conditional variable? This is possible but suboptimal.
not sure how you can really use something that doesn't exist yet, but it's easy enough to return a slot where the result will be:
function compute() {
var rez=[];
asyncCall(args, function(err, result) {
rez[0]=result;
if(rez.onchange){ rez.onchange(result); }
});
/* 'join thread here' */
return rez;
}
now, you can refer to the [0] property of the return, and once the callback comes in, compute()[0] will have the result. It will also fire an event handler you can attach to the returned array that will fire when the data updates inside the callback.
i would use something more formal like a promise or secondary callback, but that's me...
EDIT: how to integrate a callback upstream:
// sync (old and busted):
function render(){
var myView=compute();
mainDiv.innerHTML=myView;
}
//async using my re-modified compute():
function render(){
var that=compute();
that.onchange=function(e){ mainDiv.innerHTML=e; }
}
see how making it wait only added a single wrapper in the render function?
There's no await syntax in browsers that is widely available. Your options are generally limited to Callback patterns or Promises.
NodeJS follows a callback pattern for most async methods.
function someAsyncMethod(options, callback) {
//callback = function(error, data)
// when there is an error, it is the first parameter, otherwise use null
doSomethingAsync(function(){
callback(null, response);
});
}
....
someAsyncMethod({...}, function(err, data) {
if (err) return alert("OMG! FAilZ!");
// use data
});
Another common implementation is promises, such as jQuery's .ajax() method...
var px = $.ajax({...});
px.data(function(data, xhr, status){
//runs when data returns.
});
px.fail(function(err,xhr, status){
//runs when an error occurs
});
Promises are similar to events...
Of the two methods above, the callback syntax tends to be easier to implement and follow, but can lead to deeply nested callback trees, though you can use utility patterns, methods like async to overcome this.

Categories