Angular2 - Promise inside a conditional statement - javascript

I need to wait an answer from my server to say if the email is already taken or not. But I'm struggling to make this synchronously. In my if statement, typescript says that isCorrectEmail() is a void function (that I can understand but cannot solve). Any idea?
isEmailAvailable(){
return new Promise( (resolve, reject) => {
this.authService.checkemail(this.user.email).then(result => {
let res = <any> result;
if (res.code == 0){
resolve(true);
}
elseĀ resolve(false);
}, (err) => {
reject(false);
});
});
};
isCorrectEmail(){
this.isEmailAvailable().then( (result) => { return result ; } );
};
checkPersonalInfos()
{
if ( this.isCorrectEmail() == true){...}
..
}

You cannot turn an asynchronous call into a synchronous one.
You have two options: move the code which needs the use the resulting value entirely inside a then callback:
checkPersonalInfos()
{
this.isEmailAvailable().then(isAvailable => {
if (isAvailable) { ... }
}
}
Or use the async/await syntax to make it look like synchronous code, but remember it is still asynchronous so other code will run during the await and if you return a result from the function it will be wrapped inside a Promise():
async checkPersonalInfos()
{
if (await this.isEmailAvailable()) { ... }
...
}
You don't actually need your isCorrectEmail() function here as it does nothing at all to the result, but if it did something more complex so it was actually needed then it has to return the Promise:
isCorrectEmail(): Promise<boolean> {
return this.isEmailAvailable().then(result => result);
};

Related

Am I chaining Promises correctly or committing a sin?

I have not worked with Javascript in a long time, so now promises are a new concept to me. I have some operations requiring more than one asynchronous call but which I want to treat as a transaction where steps do not execute if the step before failed. Currently I chain promises by nesting and I want to return a promise to the caller.
After reading the chaining section of Mozilla's Using Promises guide, I'm not sure if what I'm doing is correct or equivalent to the "callback pyramid of doom".
Is there a cleaner way to do this (besides chaining with a guard check in each then)? Am I right in my belief that in Mozilla's example it will execute each chained then even when there is an error?
myfunction(key) => {
return new Promise((outerResolve, outerReject) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}
}).then((resolve) => {
//Now the inner most item is resolved, we are working in the 'outer' shell
if (resolve.error) {
outerReject(resolve);
} else {
//No error, continue
new Promise((resolve, reject) => {
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? reject({ error: chrome.runtime.lastError.message })
: resolve(result);
});
}).then((resolve) => {
//finally return the result to the caller
if (resolve.error) {
outerReject(resolve);
} else {
outerResolve(resolve);
}
});
}
});
});
}
Subsequent then statements are not executed (until a catch) when an exception is thrown. Also, .then returns a Promise, so you don't need to create an additional, outer Promise.
Try this example:
var p = new Promise((resolve, reject) => {
console.log('first promise, resolves');
resolve();
})
.then(() => {
throw new Error('Something failed');
})
.then(() => {
console.log('then after the error');
return('result');
});
p.then(res => console.log('success: ' + res), err => console.log('error: ' + err));
You will not see "then after the error" in the console, because that happens after an exception is thrown. But if you comment the throw statement, you will get the result you expect in the Promise.
I am not sure I understand your example entirely, but I think it could be simplified like this:
myfunction(key) => {
return new Promise((resolve, reject) => {
let item = cache.get(key);
if (item) {
resolve(item);
} else {
//we didnt have the row cached, load it from store
chrome.storage.sync.get(key, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: resolve(result);
});
}
}).then((previousData) => {
// keyBasedOnPreviousData is calculated based on previousData
chrome.storage.sync.get(keyBasedOnPreviousData, function (result) {
chrome.runtime.lastError
? throw new Error(chrome.runtime.lastError.message)
: return result;
});
});
}
It's a bit of a mess. This is my attempt at rewriting. A good thing to try to avoid is new Promise().
function chromeStorageGet(key) {
return new Promise( (res, rej) => {
chrome.storage.sync.get(key, result => {
if (chrome.runtime.lastError) {
rej(new Error(chrome.runtime.lastError.message))
} else {
res(result)
}
});
});
});
function myfunction(key) {
const item = cache.get(key) ? Promise.resolve(cache.get(key)) : chromeStorageGet(key);
return item.then( cacheResult => {
return chromeStorageGet(keyBasedOnPreviousData);
});
}
Why avoid new Promise()?
The reason for this is that you want to do every step with then(). If any error happened in any of the promises, every promise in the chain will fail and any subsequent then() will not get executed until there is a catch() handler.
Lots of promise based-code requires no error handlers, because promise-based functions always return promises and exceptions should flow all the back to the caller until there is something useful to be done with error handling.
Note that the exceptions to these 2 rules are in my chromeStorageGet function. A few notes here:
new Promise can be a quick and easy way to convert callback code to promise code.
It's usually a good idea to just create a little conversion layer for this callback-based code. If you need chrome.storage.sync in other places, maybe create a little utility that promisifies all its functions.
If there is only 1 'flow', you can just use a series of then() to complete the process, but sometimes you need to conditionally do other things. Just splitting up these complicated operations in a number of different functions can really help here.
But this:
const result = condition ? Promise.resolve() : Promise.reject();
Is almost always preferred to:
const result = new Promise( (res, rej) => {
if (condition) {
res();
} else {
rej();
}
}

Conditionally call a promise (or not), but return either result to another promise

having trouble trying to write the following code in a way that doesn't involve nested promises.
function trickyFunction(queryOptions, data) {
return new Promise((resolve, reject) => {
if (data) {
resolve(data);
} else {
// ... a bunch of conditions to check and/or modify queryOptions. These checks and mods
// are vital but only required if data is not passed in. ...
if (anErrorHappensHere) {
reject('Oh no, an error happened');
}
somePromise(queryOptions).then((result) => {
resolve(result);
});
}
}).then((result) => {
criticalOperation1(result);
// the code here is long and shouldn't be duplicated
});
}
I really don't like the .then() chain after somePromise since it's inside the new Promise, but I really don't see a way around it. If I take the conditional out of a promise, then I'd have to duplicate the criticalOperation1 code, which isn't an option here. The conditional checks in the else block should only happen if data is not passed in. Making other functions is not permitted in my case, and using async/await is also not permitted in my case.
Does anyone have any ideas? I've worked with Promises for a bit but this one is stumping me.
I would just avoid using the new Promise syntax in this case and just start the promise chain early
function trickyFunction(queryOptions, data) {
return Promise.resolve()
.then( () => {
if (data) {
return Promise.resolve(data);
} else {
// ... a bunch of conditions to check and/or modify queryOptions. These checks and mods
// are vital but only required if data is not passed in. ...
if (anErrorHappensHere) {
// Could also just throw here
return Promise.reject('Oh no, an error happened');
}
return somePromise(queryOptions);
}
})
.then((result) => {
criticalOperation1(result);
// the code here is long and shouldn't be duplicated
});
}
function trickyFunction(queryOptions, data) {
return new Promise((resolve, reject) => {
if (anErrorHappensHere) {
reject('Oh no, an error happened');
}
resolve({data, queryOptions});
}).then((obj) => {
if(obj.data){
return Promise.resolve(obj.data);
} else {
return somePromise(obj.queryOptions)
}
}).then((result) => criticalOperation1(result));
.catch((err)=> console.log(err));
}

How to return from a promise inside then block?

I'm trying to understand how promise's cascading properly works. For this, I created a function which returns a new Promise but has some callback functions in their scope:
exports.function1 = (params) => {
return new Promise((resolve, reject) => {
// do something sync
someFunctionAsyncWithCallback(params, (err, data) => { //async func
err ? reject(err) : resolve(data);
})
}).then(data => {
// do something sync again
anotherAsyncFunctionWithCallback(data, function (err, response) {
return err ? Promise.reject(err) : Promise.resolve(response);
// return err ? reject(err) : resolve(response); ?
});
})
}
Inside then block, how can I made a properly return in order to continue cascading process? In executor there are resolve/reject functions which I can call in order to continue chaining. But, once we are in then execution, these function aren't there - correct me if I'm wrong - and I don't know how to move on.
Any comment will be appreciated.
Avoid combining promise chains with callback-style APIs. Instead, wrap the callback-style API with a promise wrapper, which then lets you compose things reasonably.
The examples you've quoted look like NodeJS APIs. If you're using Node, v8 and higher have utils.promisify which can be used to quickly and easily wrap standard NodeJS-callback-style functions to functions returning promises.
// Get promise-enabled versions:
const promiseSomeFunctionAsyncWithCallback = utils.promisify(someFunctionAsyncWithCallback);
const promiseAnotherAsyncFunctionWithCallback = utils.promisify(anotherAsyncFunctionWithCallback);
// Use them:
exports.function1 = (params) => {
return promiseSomeFunctionAsyncWithCallback(params)
.then(promiseAnotherAsyncFunctionWithCallback);
})
};
If you're not using Node, or you're using an old version, there's nothing magic about utils.promisify, you can easily roll your own:
const promisify = f => return function(..args) {
return new Promise((resolve, reject) => {
f.call(this, ...args, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
Re your comment:
I have some sync code between these callback functions.. How would you handle it in your first example?
There are two styles for that:
1. Put the sync code in the then callback and chain only when you reach your next async bit:
exports.function1 = (params) => {
// Code here will run synchronously when `function1` is called
return promiseSomeFunctionAsyncWithCallback(params)
.then(result => {
// You culd have synchronous code here, which runs when
// this `then` handler is called and before we wait for the following:
return promiseAnotherAsyncFunctionWithCallback(result);
});
})
};
2. Put the sync code in its own then callback:
exports.function1 = (params) => {
// Code here will run synchronously when `function1` is called
return promiseSomeFunctionAsyncWithCallback(params)
.then(result => {
// You culd have synchronous code here, which runs when
// this `then` handler is called.
// Pass on the result:
return result;
})
.then(promiseAnotherAsyncFunctionWithCallback);
})
};
One advantage to #2 is that each distinct logical step is its own block. It does mean one additional yield back to the microtask loop at the end of this iteration of the main event loop, but that's not likely to be an issue.
You need to return another Promise:
return new Promise((res, rej) => anotherAsyncFunctionWithCallback(data, (err, data) => err ? rej(err) : res(data));
However then it would make sense to promisify the function:
const promisify = f => (...args) => new Promise((res, rej) => f(...args, (err, data) => err? rej(err) : res(data)));
const asyncF = promisify(AsyncFunctionWithCallback);
So one can do:
asyncF(1).then(asyncF).then(console.log);
you can use a flag variable for returning something.
example;
async function test(){
let flag=0;
await fetch(request).then(()=> flag=1}
if(flag==1) return;
}

How to use another promise in a function which returns a new promise?

I started learning Promises in JS and I am trying to replace my existing callback logic using promises. I wrote a function which returns a new promise, and also uses a promise of a database instance to retrieve the data. However, i am not sure if i am doing it right. Here is the code snippet,
usersService.js
var getUsers = function(queryObject) {
return new Promise(function(resolve, reject) {
dbConnection.find(queryObject)
.then(function(result) {
if (result.length > 0) {
resolve(result)
} else {
resolve(errorMessage.invalidUser())
}).catch(function(err) {
reject(err)
});
})
};
usersRouter.js
router.get('/users', function (req,res,next) {
var queryObject = { "userId":req.query.userId };
userService.getUsers(queryObject)
.then(function (data) { //some logic })
.catch(function (err) { //some logic });
});
Can i use resolve conditionally ?
If the answer is No, what is the right approach ?
Also, am i using the promise in a right manner, in the router?
Thanks in advance!
Since dbConnection.find returns a promise, you can return it directly and choose what will be pass when you will resolve it. No need to wrap it inside an other promise.
var getUsers = function (queryObject) {
return dbConnection.find(queryObject).then(function (result) {
if (result.length > 0) {
return result
} else {
return errorMessage.invalidUser()
}
})
};

NodeJS: recursive function with async request

I'm trying to transfer 2 results from 2 callback to 1 lodash function (_.union) using recursive function.
I dont understand what am I doing wrong! I keep getting "undefined".
Here is my code:
EDITED:
My new code with the "promise" technique
the first function that check things in the remote DB-
function findFiles(kw, callback){
if (_.isArray(kw)) {return callback(kw)};
return new Promise((resolve, reject) => {
console.log(kw);
word.aggregate([
{ $match: { keyWord: kw } },
{ $project: { filesFound: '$filesFound.fileName' , '_id':0} },
{ $sort: { fileName: 1 } }
],function(err, obj){
console.log('checked' + kw);
console.log(obj);
if (err) return reject(err);
else
return resolve(obj[0].filesFound);//obj[0].filesFound
})
})
}
The main function:
function searchOperation(query, callback){
var stack=[];
if (!(_.includes(query, 'OR')) && !(_.includes(query, 'AND')) && !(_.includes(query, 'NOT'))){
findFiles(query)
.then((item) => {
console.log(item+'********');
callback(item)
})
.catch((err) => {
console.log(err)
})
}
else{
wordsArr = _.split(query, " ");
console.log("+++++:" + wordsArr);
wordsArr.forEach(function(w){
console.log('first check:'+w);
if(_.isEmpty(stack)){
if(_.includes(w, 'OR')){
console.log('found OR');
var statement = [];
console.log('query is:'+query);
statement = _.split(query, w, 2);
console.log(statement[0]+' , '+statement[1]);
return new Promise((resolve, reject)=>{
resolve(_.union(searchOperation(statement[0]),searchOperation(statement[1])))
})
//ANOTHER OPTION:
// searchOperation(statement[0],function(arr1){
// console.log('arr1');
// console.log('done part 1!');
// searchOperation(statement[1],function(arr2){
// console.log('who called arr2?');
// return(_.union(arr1,arr2));
// })
// });
}
}
})
}
}
now, inside the function findFile() the console.log return what i need. but then I need to use both returned values in another function (union) and it returns undefined.
in the main thread:
searchOperation('Expression1 OR Expression2', function(result){
res.json(result);
})
now i'm sure: something goes WRONG in the recursive function and the async of node...
I need it to work recursively and could get complicate expressions like:
'((A NOT B) AND (C OR D))'
does some know what is the right way to write it either with Promise or async.waterfall ??
thanks in advance!!!
Your code doesn't work because you're trying to get an Async response in a Synchronous fashion.
Look into Promises.

Categories

Resources