I am trying to understand deferred and promise. I dont want to use any library angularfire etc., before understanding the core concept. This is what i am trying to do and always getting a wrong status. Please advise.
........
var defObj = $.Deferred();
var fbref = new Firebase(<<firebase url>>);
defObj.done(function() {
console.log('Success')
}
);
defObj.fail(function() {
console.log('Fail')
}
);
defObj.resolve(
fbref.authAnonymously(function(error, authData) {
if (error) {
defObj.reject();
}
/*
else if (authData) {
defObj.resolve();
}
*/
});
return defObj.promise();
........
Pls ignore any syntax errors. Earlier I wrapped the fbref.authAnonymously call in a seperate function. In debug mode it was falling to fail but in run mode it was always going to success.
I am sure my firebase instance is not enabled for anonymous authentication.
edited : misspelt title.
Promises are now an official part of JavaScript and you can use them in the latest browsers without a library.
function authAnonymously() {
// 1
var promise = new Promise(
function(resolve, reject) {
var ref = new Firebase(<<firebase url>>);
ref.authAnonymously(function(error, authData) {
if (error) {
reject(error); // 2
} else {
resolve(authData); // 3
}
});
});
}
authAnonymously()
.then((authData) => console.log(authData)) // 4
.catch((error) => console.error(error)); // 5
Here are the five steps in this example
Create a Promise constructor
If the asynchronous action is to error, mark it with the reject() function.
If the asynchronous action is to succeed, mark it with the resolve() function.
Call the authAnonymously() function and begin the promise chain with the then() function. When successful this function will fire off.
Continue the promise chain with the error() function. If the error occurs, the catch() function won't fire, but this error() function will.
Promises work well for one time callbacks. For Firebase, this is great for authentication methods and once() calls. This is not great though for repeated callbacks, like the on() function.
Related
Basically I have a construction like;
// Library function
function foo(){
return new Promise((resolve, reject) =>{
// Do lots of stuff, like rendering a prompt
// On user action
if(userDidSomething){
resolve(user_input);
}
if(userCanceled){
// On user cancel
reject('User canceled');
}
}).catch("Default error (usually canceling whatever it is, which means; do nothing)");
}
// Function to call library function with predefined settings for this website
function bar(){
// Have some defaults set here, like which kind of prompt it should be
return foo();
}
// Where the function will actually be used
function baz(){
bar().then("do some things");
}
I've worked my way around this issue some years ago but unfortunately forgot how I actually managed to do that.
The goal: Have one standard catch handle things for me on the library level. If I want to overrule it, I can always do that later. So I guess it's: Break the chain.
The problem: Having the catch before the then, causes the then to be triggered once I have dealt with the catch (which is; ignoring it, in this case)
My current solution: I'm using throw on the library-level catch, this causes the promise to throw an uncaught error exception.
However, this completely clutters up my console with errors which aren't really errors.
The problem is that the entire resolve/reject of the promise is being handled by the library. That promise gets returned around and I only call it way later.
This is a function I'm calling about 300 times throughout my project, and I don't want to be putting custom error handling on every single one of those function calls when the handling of this should be "don't do anything, really".
What you are asking for is not really possible using native Promises because that's not how they were intended to be used.
You can, though, create a custom Promise class that does this. Note that muting all rejections is a bad idea because you won't see if your code errors out. To go around that, only a special value (SpecialPromise.CANCELED) is treated differently. The code has to track whether a .catch is attached to it. When the promise encounters the special value and it has no catch callback at the moment, it quickly attaches a no-op catch callback to silence the error:
class SilentPromise extends Promise{
constructor(executor){
super((resolve, reject) => {
executor(
resolve,
e => {
if(e === this.constructor.CANCELED && !this._hasCatch){
this.catch(() => {})
}
reject(e)
}
)
})
this._hasCatch = false
}
then(success, error){
this._hasCatch = true
return super.then(success, error)
}
catch(error){
this._hasCatch = true
return super.catch(error)
}
catchIfNotCanceled(error){
this.catch(e => {
if(e === this.constructor.CANCELED)
throw e
return error(e)
})
}
}
SilentPromise[Symbol.species] = SilentPromise
SilentPromise.CANCELED = Symbol('CANCELED')
You can convert existing promises between SilentPromise and Promise using SilentPromise.resolve() and Promise.resolve().
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()
I want this function tagFindOrCreate to only execute if the first function is finished:
func.tweetCreate(bmTweet, user)
.then(function () {
func.tagFindOrCreate(bmTweet, bmtTag, user)
})
Help me create a promise for this function:
tweetCreate: function (tweet, user) {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet)
user[0].save()
console.log("Tweet saved.")
return Promise.resolve()
})
}
This would be as follows:
tweetCreate: function (tweet, user) {
return new Promise(resolve => {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet);
user[0].save();
console.log("Tweet saved.")
resolve();
})
}
};
Since Tweet is a mongoose model, its create method will already return a promise as long as you don't pass a callback. This means you can move your callback logic to where promise resolution occurs. The simplest way to do this would be to use an async function.
tweetCreate: async function (tweetContents, user) {
const createdTweet = await Tweet.create(tweetContents);
user[0].tweets.push(createdTweet);
user[0].save();
console.log('tweet saved');
}
A note on error handling: An async function will already return a promise or potentially throw an error (if there is an error in Tweet.create). The above code will propagate the error, so make sure that if you are using async/await you wrap your calling code in try/catch or make use of .catch to handle the errors where it's needed. It's up to the logic of your app to decide whether you need to catch the error in tweetCreate itself, or whether you can propagate it into the application code level where it can be caught and handled, but just be aware of the need to handle potential promise errors.
For the sake of completeness, you can promisify Tweet.create. It's common for library methods to return promises nowadays, so manual promisification is rarely necessary. Keep this in mind if you feel the need to promisify ... the library may already have a mechanism for it.
You can do this manually simply by using a Promise constructor. This takes a callback which takes a resolve argument which you can call from within another callback to resolve the promise:
return Promise(resolve => {
Tweet.create(tweet, (error, createdTweet) {
...
resolve();
});
});
Node.js has a built-in promisify function as well, so using a Promise constructor is probably unnecessary for this purpose. You could do:
const createTweet = util.promisify(Tweet.create);
const createdTweet = await createTweet(tweet);
...
NOTE: the above is just an example. It's not necessary to do this with mongoose models.
You need to use the promise constructor to create a promise and tweetCreate() should return that promise.
Call to Tweet.create(...) should be inside the executor function (function that is passed to the promise constructor) and from inside of the callback function of Tweet.create(...), you need to call the resolve() function to fulfil the promise.
You need to change the implementation of your function to as shown below:
tweetCreate: function (tweet, user) {
return new Promise((resolve, reject) => {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet);
user[0].save();
resolve(); // <--- this will resolve the promise
});
});
}
Calling resolve() will fulfil the promise leading to the invocation of the callback function of the then() method.
Edit
You mentioned in a comment that Tweet is a mongoose model; In that case, you don't need a explicitly create a promise. Mongoose provides a promise-based API for creating and saving documents in the database and that is what you should use instead of creating promises yourself.
Below is a simplification of my code, I'm basicly running a function, that creates a Promise inside the function and returns it. For some reason though, testing with console.time(), it would appear that the code is actually blocking. The x.root function takes roughly 200ms to run and both console.time() tests give pretty much 200ms. Now if I did the age old trick of wrapping the function in setTimeout, the problem disappears, but I'd like to know what I'm doing wrong here?
I'd really prefer being able to create, resolve and reject the promises inside my helper function and then just call my function followed by then and catch without having to create Promises on an earlier level. What's the malfunction here?
parseroot = function(params) {
return new Promise(function(resolve, reject) {
try {
var parsed_html = x.root(params);
x.replacecontents(params.target, parsed_html);
resolve(true);
}
catch(e) {
reject(e);
}
});
}
console.time("Test 1");
console.time("Test 2");
var el = document.querySelector("#custom-element");
el.parseroot({
section:"list",
target: "#list-container",
}).then(function(response) {
console.info("searchresult > list() success");
console.timeEnd("Test 2");
});
console.timeEnd("Test 1");
Promises don't turn synchronous code into asynchronous code.
If the function you pass to Promise blocks, then the promise will block too.
While trying to move my code to promises after working only with callbacks,
(without breaking the function's interface) I've encountered an issue.
in a code example like this:
function callMeWithCallback(args, next) {
Promise.resolve()
.then(()=> {
return next("some error will be thrown here");
}).catch((error)=> {
return next("Error in callMeWithCallback func");
});
}
callMeWithCallback(args, function(){
throw "some error";
})
What happens is that after resolving the promise in callMeWithCallback func and calling the callback once, an error is thrown, and the code comes back the catch in the callMeWithCallback function and calls again the callback.
I would like the function callMeWithCallback to call the call back only once (wether i case of an error or not) what changes do I need to imply?
I warmly recommend that you use a library like bluebird that normalizes this for you - your code would be:
function callMeWithCallback(args, next) {
// in real code always reject with `Error` objects
var p = Promise.reject("some error will be thrown here");
p.asCallback(next); // converts a promise API to a callback one, `throw`s.
return p;
}
This guarantees "next" will be called once at most.
If you do not want bluebird you can implement this yourself:-
function asCallback(promise, callback) {
promise.then(v => callback(null, v), e => callback(e));
}
Which would be fine as long as you keep the calls in one place. The important part is to not dispatch the calls to "next" yourself.