Integrate a callback logic based library function into promise chain [duplicate] - javascript

This question already has answers here:
How to create a AngularJS promise from a callback-based API
(2 answers)
Closed 4 years ago.
To handle promises I return and chain them with .then(). I must however use a third party library that expects a callback and that does not return a promise.
For clarity, a fake example:
person.sayHello()
.then( response => introduceMyself() )
.then( name => externalLibrary.storeAndGetInfo(name) )
.then( info => saySomeInfo(info) )
.catch( err => console.log(err) );
introduceMyself(){
return asyncFunctionToGetAndSayMyName();
}
sayDomeInfo(info){
console.log(info);
}
My problem is that externalLibrary.storeAndGetInfo expects these params:
storeAndGetInfo(string, callback(valueThatINeedForMyNextChainedFunction));
I have the feeling that I could wrap the external library function in a chainable function (one that returns a promise), and then use the library q to defer and resolve the callback function, but then I'm stuck as I don't know to actually implement it. Or is there another way?
PS in case it makes a difference, this is in a angularjs app

You should wrap your external library's call with a function that returns a a deferred promise:
function promisedStore (name) {
var deferred = Q.defer(); //initialize deferred
externalLibrary.storeAndGetInfo(name, function(error, result) {
if (error) {
deferred.reject(new Error(error)); //reject promise if error in cb
} else {
deferred.resolve(result); //resolve promise if no error in cb
}
});
return deferred.promise;
}

Related

Why functions as arguments (resolve, reject) are used in the Promise syntax rather than a simple return and throw? [duplicate]

This question already has answers here:
Promise constructor with reject call vs throwing error
(4 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
This is a 'why' question, not a suggestion. I know the following function is incorrect, but it helps to clarify my question: I want to know what is wrong with this view (i.e. what requirement of Promise I am missing here). Answers can help other like me to get out of confusion. Please provide an example where the following requirement of Promise is necessary:
I (incorrectly) assumed Promises are for deferring execution of functions and assigning a chain of then & catch. I need to know the following: Why does JavaScript Promise uses (resolve, reject) instead of a parameter-less callback that returns or throws?
In a naive and incorrect view, the Promise could have been used in a simpler way (without two arguments resolve, reject) like the following:
/*new*/ IncorrectPromise(()=>{
let x = Math.random()>0.5;
console.log('promise 1');
if (x) {
return 'head1';
} else {
throw new Error('tail1');
}
})
.then((d)=>{
console.log('.then() d=', d);
})
.catch( (ex) =>{
console.log('.catch() e=', ex.message);
});
Instead of the Promise's way:
new Promise( (resolve_, reject_) => {
let y = Math.random()>0.5;
console.log('promise 2');
if (y) {
resolve_('head2');
} else {
reject_(new Error('tail2'));
}
})
.then((d)=>{
console.log(' .then() d=', d);
})
.catch( (ex) =>{
console.log(' .catch() e=', ex.message);
});
i.e. when the control flow exits the body of the callback of the promise, resolve or reject are used based on whether the exit was caused by a return or a throw.
My question is, why promises use the current syntax? The answer will be an example which cannot be done with this (naive) function.
The above syntax can be easily emulated with the following definition (for simplicity, ignore the fact that IncorrectPromise is not a constructor, hence does not need the new operator):
function IncorrectPromise(callback) {
return new Promise( (res, rej) => {
try {
res( callback() );
} catch (err) {
rej(err);
}
});
}
What would have been the shortcoming of this simpler usage syntax? What was the intention of the designers or the Promise to use (resolve, reject)?

Promise.all doesn't return none of it's promises if one of them fail [duplicate]

This question already has answers here:
Wait until all promises complete even if some rejected
(20 answers)
ES6 Promise.all() error handle - Is .settle() needed? [duplicate]
(1 answer)
Closed 4 years ago.
I had posted a question earlier about Promise.all and d3.js v5, but another question come up regarding this piece of code:
var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];
files.forEach(function(url) {
promises.push(d3.json(url))
});
Promise.all(promises).then(function(values) {
console.log(values)
});
If one of the URL's is invalid, the Promise.all doesn't return any of the results; in other words, all responses must be valid for the Promise.all to return the values. How can one get the other responses in the case of an error in one of the URL's?
That's how Promise.all works. But if you want to get it work for rejected promises, you can do it like this:
var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];
files.forEach(function(url) {
promises.push(
d3.json(url)
.then(function(data) {
return {success: true, data: data};
}, function() {
return {success: false};
})
)
});
Promise.all(promises).then(function(values) {
console.log(values)
});
Note that Promise#then can accept two functions as arguments, first one is called when the promise is resolved, and the second one is called when its rejected.
You can manually resolve the rejected promise, and can return an identifier to know if the call resulted in success or failure, like I did using the success key.
Try to wrap each promise to your custom promise and resolve each of them.
Here is example:
const wrappedPromises = promises.map(promise => {
if (promise) {
return new Promise((resolve, reject) => {
promise.then(resolve).catch(resolve);
});
}
});
Promise.all(wrappedPromises).then(function(values) {
console.log(values)
});
You want something like Promise.settle. You can get that with Bluebird and .reflect(): http://bluebirdjs.com/docs/api/reflect.html
function settle (promises) {
return Promise.all(promises.map(promise => promise.reflect()));
}
var x = [Promise.resolve(1), Promise.reject(new Error("omg")), Promise.resolve(2)];
settle(x).then(console.log)
<script src="//cdn.jsdelivr.net/bluebird/3.5.0/bluebird.js"></script>
With Promise.all you need to make sure that every Promise resolves (meaning that it doesn't reject). it's very easy to accomplish this, just handle rejection and recover from it. For example:
var files = ["data1.json", "data2.json", "data3.json"];
var promises = files.map(function(url) {
return d3.json(url)
.catch(function (err) {
return {
error: err
}
})
});
Promise.all(promises).then(function(values) {
console.log(values)
});
So all you need to add is catch block:
.catch(function (err) {
return {
error: err
}
}
Write your own version of Promise.all. Keep track of resolved and rejected promises and return whatever array you see fit once all promises are either resolved or rejected.

Resolving chained Angular Promises synchronously [duplicate]

This question already has an answer here:
How to chain and share prior results with Promises [duplicate]
(1 answer)
Closed 5 years ago.
I have a resolve promise function that uses $q service, where there is some generic code to resolve/reject based on certain conditions. I have a scenario wherein I would have to execute api2 only after api1 is successfully resolved. But both the calls are happening asynchronously. I have pasted the pseudo code below. Please help. Thanks a lot in advance.
var resolvePromise = function(promise)
{
var defer = $q.defer();
promise.then(function(response)
if(certain conditions are true)
{
defer.reject(err)
}
defer.resolve();
)
.catch(function(errors){
defer.reject(errors);
})
return defer.promise;
}
function synchronousCalls()
{
var promise1 = service.getApi1();
var promise2 = service.getApi2();
return resolvePromise(promise1).then(function(){
return resolvePromise(promise2);
})
}
function getData()
{
synchronousCalls().then(function(){
console.log("synchronous run of apis ended");
})
}
You don't need the resolvePromise function. Have getApi1 and getApi2 return Promises directly that you can .then(). Additionally, calls to functions that return Promises don't stop execution context. You are firing calls to both APIs immediately and not waiting for the first to finish. You need to call to getApi1(), and .then() the Promise that should be returned from it. Consider the following code:
// This says, fire them both immediately
var promise1 = service.getApi1();
var promise2 = service.getApi2();
// Your call should look something like this
service
.getApi1()
.then(function (api1Response) {
// If I'm in here, I know that the request to service 1 is done
return service
.getApi2();
}).then(function (api2Response) {
// If I'm in here, I know that the request to service 2 is done
console.log(api2Response);
})
.catch(function (err) {
console.log("Something has gone wrong");
});
Both of you getApi functions should look something like this, where the main thing they do is return something (like a Promise) with a .then() method.
function getApi1() {
// This is returning a Promise
return $http
.get("some/resource/on/the/server.json")
.then(function (response) {
/*
* Here I'm just peeling out the data from the response
* because I don't actually care about the details of the
* response, just the data
*/
return response.data;
});
}
Change the synchronousCalls to
function synchronousCalls()
{
return service.getApi1().then(resolvePromise).then(service.getApi2).then(resolvePromise);
}

Let a promise return something [duplicate]

This question already has answers here:
How to block for a javascript promise and return the resolved result? [duplicate]
(2 answers)
Closed 5 years ago.
I have to use a method that returns a promise and that is inside a function. I want to return a value for the parent function in the .then() of the promise.
returnSomething():boolean{
theFunctionThatReturnsAPromise()
.then(
//return true for the returnSomething function here
).catch(
//return false for the returnSomething function here
);
}
How can I do this with typescript/Javascript?
You can use async/await for this.
async function foo() {
try {
var val = await theFunctionThatReturnsAPromise();
console.log(val);
}
catch(err) {
console.log('Error: ', err.message);
}
}
But the return value is still going to be a Promise, since it is asynchronous.
For a better understanding you might want to read this tutorial.
You can't return something directly because the thing you want to return isn't immediately available. That's the whole reason we use asynchronous things like promises. It's hard to know exactly what you are doing from a couple lines of code, but in general you just want to return the promise and allow the caller of the function to deal with it.
For example:
returnSomething():Promise<boolean>{
return theFunctionThatReturnsAPromise()
}
Then the caller can deal with the value like:
returnSomething()
.then(result => {
if (result) { //etc.}
}
.catch( err => { console.log("an error happened", err)}

How to avoid deferred antipattern [duplicate]

This question already has answers here:
Is there a way to return early in deferred promise?
(2 answers)
Closed 6 years ago.
It's being hard to learn how to avoid the deferred antipatern with the info I could find. I'm using Q library for Nodejs.
As it is possible to read, basically, we've to try to do not reject or answer to a promise with deferred.reject or deferred.resolve.
deferred.resolve must be replaced by a return sentence, so that point is quite simple.
The problem comes when I want use a promise inside a function which must reject the execution in some cases which aren't application errors. For example:
Services.data.isNotForbiddenFieldToUpdate(bodyKeys,forbidden)
.then(() => console.log('Finish'))
Where
isNotForbiddenFieldToUpdate: (fieldsToUpdate,forbiddenFields) => {
var deferred = Q.defer();
//DO A QUERY AND STORE IN result PARAM
if(err) deferred.reject(err)
else if(! result) deferred.reject(new Error('Query is empty.'));
else deferred,resolve();
return deferred.promise;
}
In this case, is not possible to return something different from deferred.promise. If I remove this and return true, the error is that then is unknown.
How could I manage this kind of code without using deferred if is possible? Thanks.
isNotForbiddenFieldToUpdate: (fieldsToUpdate,forbiddenFields) => {
var deferred = Q.defer();
//DO A QUERY AND STORE IN result PARAM
At this point, assuming that the "QUERY" is an asynchronous operation, you will get back a promise. So you likely don't need to create another promise, just reuse the one coming from your "QUERY".
return yourAsyncQuery();
Or, if you need to add things to the result of your "QUERY", then you have to give it a callback to execute when it completes. Inside that callback, you resolve or reject the Promise (Q).
yourAsyncQuery().then(
function(result) {
if (! result)
deferred.reject(new Error('Query is empty.'));
// do more stuff with 'result'.
deferred.resolve(result);
},
function(error) {
deferred.reject(error);
}
);
return deferred.promise;
}
I don't know how in Q is, but with native promises you can do as follows:
isNotForbiddenFieldToUpdate: (fieldsToUpdate,forbiddenFields) =>
new Promise((resolve, reject) => {
//DO A QUERY AND STORE IN result PARAM
if(err){
reject(err);
} else if(! result){
reject(new Error('Query is empty.'));
} else {
resolve();
}
}
I guess with Q should be similar. Anyway, unless you need a very specific Q functionality, I would rather use native Promises.

Categories