Intentionally not returning Bluebird Promise - javascript

I have the piece of code below. Want to call the callback which may return a promise. Resolve it. In case if the promise failed, log it. The caller should NOT know about all this and should return without waiting for the promise to fulfill. That's why I'm not returning the promise. This causes the following error:
(node:21146) Warning: a promise was created in a handler at internal/timers.js:456:21 but was not returned from it, see http goo.gl/rRqMUw
at Function.Promise.cast (bluebird/js/release/promise.js:225:13)
I've read the docs and they recommend returning null to prevent the warning from happening. Nevertheless, the warning still pops out. Also, do not want to disable the warning globally.
private _trigger(cb : () => Resolvable<any>)
{
try
{
const res = cb();
const prom = Promise.resolve(res);
prom.catch(reason => {
this.logger.error("ERROR: ", reason);
})
}
catch(reason)
{
this.logger.error("ERROR: ", reason);
}
return null;
}

The internal Promise should resolve to a value of null to silence the warning - this will tell Bluebird "The Promise isn't being returned, but since it resolves to null, it doesn't contain a useful result, so this is deliberate"; returning it wouldn't give the caller useful data. You can do something like:
const prom = Promise.resolve(res)
.catch(reason => {
this.logger.error("ERROR: ", reason);
})
.then(() => null);

Related

How to avoid ` PromiseRejectionHandledWarning: Promise rejection was handled asynchronously`?

I'm getting PromiseRejectionHandledWarning: Promise rejection was handled asynchronously warning for my code, it also fails Jest tests. I've read that's Promise rejection should be handled at the same place they're defined and seem to understand the logic and the reasons. But it looks like something is wrong with my understanding as what I expect to be synchronous handling still cause warning.
My typescript code is below.
Promise, that is rejected is sendNotification(subscription, JSON.stringify(message)). From my understanding it's handled right away using .catch call, but probably I'm missing something. Can anyone, please, point me to my mistake?
private notify(tokens: string[], message: IIterableObject): Promise<any> {
const promises = [];
tokens.forEach(token => {
const subscription = JSON.parse(token);
this.logger.log('Sending notification to subscription', {subscription, message})
const result = this.WebPushClient
.sendNotification(subscription, JSON.stringify(message))
.catch(e => {
this.logger.log('Send notification failed, revoking token', {
subscription,
message,
token,
e
})
return this.revokeToken(token).catch(error => {
this.logger.error('Failed to revoke token', {
token,
error,
})
return Promise.resolve();
});
});
promises.push(result);
});
return Promise.all(promises);
}
I found the issue.
In Jest you can't just mock return value with rejected promise. You need to wrap it in special workaround function:
const safeReject = p => {
p.catch(ignore=>ignore);
return p;
};
And then wrap the Promise before return it
const sendNotification = jest.fn();
sendNotification.mockReturnValue(safeReject(Promise.reject(Error('test error'))));
You can also use mockImplementation (I'm using jest 28).
jest.fn().mockImplementation(() => Promise.reject(new Error('test')))

Extracting object returned from promise to push to an array, returning as Promise {<pending>} with [[PromiseValue]] object [duplicate]

My code:
let AuthUser = data => {
return google.login(data.username, data.password).then(token => { return token } )
}
And when i try to run something like this:
let userToken = AuthUser(data)
console.log(userToken)
I'm getting:
Promise { <pending> }
But why?
My main goal is to get token from google.login(data.username, data.password) which returns a promise, into a variable. And only then preform some actions.
The promise will always log pending as long as its results are not resolved yet. You must call .then on the promise to capture the results regardless of the promise state (resolved or still pending):
let AuthUser = function(data) {
return google.login(data.username, data.password).then(token => { return token } )
}
let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }
userToken.then(function(result) {
console.log(result) // "Some User token"
})
Why is that?
Promises are forward direction only; You can only resolve them once. The resolved value of a Promise is passed to its .then or .catch methods.
Details
According to the Promises/A+ spec:
The promise resolution procedure is an abstract operation taking as
input a promise and a value, which we denote as [[Resolve]](promise,
x). If x is a thenable, it attempts to make promise adopt the state of
x, under the assumption that x behaves at least somewhat like a
promise. Otherwise, it fulfills promise with the value x.
This treatment of thenables allows promise implementations to
interoperate, as long as they expose a Promises/A+-compliant then
method. It also allows Promises/A+ implementations to “assimilate”
nonconformant implementations with reasonable then methods.
This spec is a little hard to parse, so let's break it down. The rule is:
If the function in the .then handler returns a value, then the Promise resolves with that value. If the handler returns another Promise, then the original Promise resolves with the resolved value of the chained Promise. The next .then handler will always contain the resolved value of the chained promise returned in the preceding .then.
The way it actually works is described below in more detail:
1. The return of the .then function will be the resolved value of the promise.
function initPromise() {
return new Promise(function(res, rej) {
res("initResolve");
})
}
initPromise()
.then(function(result) {
console.log(result); // "initResolve"
return "normalReturn";
})
.then(function(result) {
console.log(result); // "normalReturn"
});
2. If the .then function returns a Promise, then the resolved value of that chained promise is passed to the following .then.
function initPromise() {
return new Promise(function(res, rej) {
res("initResolve");
})
}
initPromise()
.then(function(result) {
console.log(result); // "initResolve"
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve("secondPromise");
}, 1000)
})
})
.then(function(result) {
console.log(result); // "secondPromise"
});
I know this question was asked 2 years ago, but I run into the same issue and the answer for the problem is since ES2017, that you can simply await the functions return value (as of now, only works in async functions), like:
let AuthUser = function(data) {
return google.login(data.username, data.password)
}
let userToken = await AuthUser(data)
console.log(userToken) // your data
The then method returns a pending promise which can be resolved asynchronously by the return value of a result handler registered in the call to then, or rejected by throwing an error inside the handler called.
So calling AuthUser will not suddenly log the user in synchronously, but returns a promise whose then registered handlers will be called after the login succeeds ( or fails). I would suggest triggering all login processing by a then clause of the login promise. E.G. using named functions to highlight the sequence of flow:
let AuthUser = data => { // just the login promise
return google.login(data.username, data.password);
};
AuthUser(data).then( processLogin).catch(loginFail);
function processLogin( token) {
// do logged in stuff:
// enable, initiate, or do things after login
}
function loginFail( err) {
console.log("login failed: " + err);
}
If that situation happens for a multiple values like an array.
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
You can use Promise.all() this will resolve all promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
See the MDN section on Promises. In particular, look at the return type of then().
To log in, the user-agent has to submit a request to the server and wait to receive a response. Since making your application totally stop execution during a request round-trip usually makes for a bad user experience, practically every JS function that logs you in (or performs any other form of server interaction) will use a Promise, or something very much like it, to deliver results asynchronously.
Now, also notice that return statements are always evaluated in the context of the function they appear in. So when you wrote:
let AuthUser = data => {
return google
.login(data.username, data.password)
.then( token => {
return token;
});
};
the statement return token; meant that the anonymous function being passed into then() should return the token, not that the AuthUser function should. What AuthUser returns is the result of calling google.login(username, password).then(callback);, which happens to be a Promise.
Ultimately your callback token => { return token; } does nothing; instead, your input to then() needs to be a function that actually handles the token in some way.
Your Promise is pending, complete it by
userToken.then(function(result){
console.log(result)
})
after your remaining code.
All this code does is that .then() completes your promise & captures the end result in result variable & print result in console.
Keep in mind, you cannot store the result in global variable.
Hope that explanation might help you.
I had the same issue earlier, but my situation was a bit different in the front-end. I'll share my scenario anyway, maybe someone might find it useful.
I had an api call to /api/user/register in the frontend with email, password and username as request body. On submitting the form(register form), a handler function is called which initiates the fetch call to /api/user/register. I used the event.preventDefault() in the beginning line of this handler function, all other lines,like forming the request body as well the fetch call was written after the event.preventDefault(). This returned a pending promise.
But when I put the request body formation code above the event.preventDefault(), it returned the real promise. Like this:
event.preventDefault();
const data = {
'email': email,
'password': password
}
fetch(...)
...
instead of :
const data = {
'email': email,
'password': password
}
event.preventDefault();
fetch(...)
...
Try this
var number1 = document.getElementById("number1");
var number2 = document.getElementById("number2");
startAsync.addEventListener("click", function() {
if (number1.value > 0 && number2.value > 0) {
asyncTest(parseInt(number1.value), parseInt(number2.value)).then(function(result) {
document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
});
} else {
asyncTest(1, 2).then(function(result) {
document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
});
}
});
async function asyncTest(a, b) {
return await (a + b);
};
<button id="startAsync">start Async function</button><br />
<input type="number" id="number1" /><br />
<input type="number" id="number2" /><br />
<span id="promiseResolved"></span><br />
Im my case (JS) I forgot to add await

Using promises with Node JS express

I am newbie to promises, I am trying to understand how do they work.
Here my questions at first:
When request is handled in a route function, does it wait for all promises, I mean that when I am using promise or callback it is a new scope and execution continues further.
If I keep a req/res objects for example in timer and then respond to user, what will user see ? A request will just be blocked until I explicitly send response ?
So I have encountered the following problems.
Here is my route.
router.post('book', authHandler.provideMiddleware(), (req, res) => {
bookManager.createBook(req.body, {
onSuccess: function (data) {
respondSuccess(res,HttpStatus.OK, {'data': data});
},
onError: function (message) {
respondError(res, HttpStatus.HTTP_STATUS.BAD_REQUEST, {'error': message});
}
});
});
Inside bookmanager I have the following
createBook(data, hook) {
let book = createBookFromRequest(data);
let verifyData = new Promise((resolve, reject) => {
let valid = checkBookData(book);
if(valid) {
resolve(book);
}
else {
reject("Invalid data");
}
});
let createBook = new Promise((resolve, reject) => {
book.save((err, result) => {
if (!err) {
reject("Error while saving");
}
else {
resolve(result);
}
});
});
verifyData
.then(() => {
return createBook;
})
.then((data) => {
hook.onSuccess(data);
})
.catch((error) => {
hook.onError(error);
});
}
My idea is to chain multiple functions and if any error occurred, call hook.onError method, otherwise call on success.
I have several problems here.
When error is thrown, my book is still created.
I have the following error
node:8753) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: Can't set headers after they are sent.
I want to use the approach like Rx (Reactive Extensions).
Could someone explain what is wrong and how do promises really work in this case ?
1. When request is handled in a route function, does it wait for all promises, I mean that when I am using promise or callback it is a new scope and execution continues further.
It waits for you to send a response via res. You don't have to do that in response to the event, it's absolutely normal for it to be later, after an asynchronous process (like a promise resolution) completes.
2. If I keep a req/res objects for example in timer and then respond to user, what will user see ? A request will just be blocked until I explicitly send response ?
Yes.
I have several problems here.
1. When error is thrown, my book is still created.
You're always starting the process of creating the book, regardless of whether the data was verified as correct. new Promise starts the work.
2. I have the following error
node:8753) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: Can't set headers after they are sent.
You're creating a promise and storing it in createBook, and never handling rejections of that promise if verifyData rejects. So you get an unhandled promise rejection.
You can get rid of the entire new Promise around saving the book, and just put it in the verifyData chain; see comments:
createBook(data, hook) {
let book = createBookFromRequest(data);
let verifyData = new Promise((resolve, reject) => {
let valid = checkBookData(book);
if (valid) {
resolve(book);
}
else {
reject("Invalid data");
}
});
verifyData
.then(() => book.save()) // The chain takes on the state of the promise
// returned by `book.save`
.then(data => {
hook.onSuccess(data);
})
.catch((error) => {
hook.onError(error);
});
}
In that, I'm assuming createBookFromRequest and checkBookData are both synchronous processes, as that's how you're using them.
And actually, given that's the case, I don't see any need for the promise you're creating to verify the data. So it could be simpler:
createBook(data, hook) {
let book = createBookFromRequest(data);
if (checkBookData(book)) {
book.save()
.then(_ => hook.onSuccess(data))
.catch(error => hook.onError(error));
} else {
hook.onError("Invalid data");
}
}

I can't get the value of "result" in Node.js

In my console.log(info), I want to get the value of "result". But when I use console.log(info), I get Promise { <pending> }:
var info=new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).then(result => {
return result;
}).catch(err => {
console.log("error: " + err)
});
console.log(info);
I would like to get info == result. How can I do it?
Thanks
What happens here
First some explanation of what happens here. When you do something like this:
var info = new Promise((resolve, reject) => {
// ...
}).then(result => {
// ...
}).catch(err => {
// ...
});
then what ends up as the value of the info variable is a promise. That's because you start with a promise returned by the new Promise() constructor, you invoke its .then() method which returns a second promise, and on that second promise you invoke the .catch() method which returns a third promise - and this third promise is what gets saved into the info variable.
All of those method calls return immediately before the original HTTP request is finished so when you reach the next line:
console.log(info);
it's impossible to access the value of the response from the request() call because it didn't happen yet (the request() callback hasn't been called yet at this point). The info variable has a promise which is an object that you can use to register the callbacks that you want run when the value is eventually available. When you pass it to the console.log() it prints that it's a promise.
How to get the value
Now, when you want to print the value when it's finally available then you can attach a promise resolution callback to the promise that you have e.g. with a code like this:
info.then((value) => {
// you can use the value here
console.log('Value:', value);
}).catch((err) => {
// the promise got rejected
console.log('Error:', err);
});
If you are using a relatively recent version of Node (7.0+) then you could use await if you are inside of a function declared with an async keyword, to get the resolution value of the promise like this:
(async function () {
let value = await info;
console.log(value);
})();
or shorter:
(async () => {
console.log(await info);
})();
(If you are already inside of an async function then you don't need the (async () => { ... })(); wrapper.)
How it works
What the await keyword does is it yields the promise from an implicit generator function that passes the control to the outer coroutine control code which attaches a resolution and rejection handlers to that yielded promise and starts the generator again by either returning the resolved value from the await operator or raising an exception if the promise was rejected. The generator can then continue using the return value and catching the exception, or it can let the exception bubble to the outer blocks where it can be caught or converted to a rejection of the implicit promise returned by the async function if not handled along the way.
How you can use it
It may seem complicated but from the point of view of your code it lets you do things like:
let value = await fun();
(where fun() is a function that returns a promise) and have the resolved value of the promise available in the value variable (the real value, not a promise).
Remember that the await keyword throws an exception when the promise in question gets rejected. To handle that case you can use a try/catch block:
try {
let value = await fun();
// promise got resolved, you have value here:
console.log('Value:', value);
} catch (error) {
// promise got rejected, you have error here:
console.log('Error:', error);
}
which is equivalent of this code without the new syntax:
fun().then((value) => {
// promise got resolved, you have value here:
console.log('Value:', value);
}).catch((error) => {
// promise got rejected, you have error here:
console.log('Error:', error);
});
with the main difference being the variable scoping when you await on multiple promises in a single try block as opposed to using multiple chained .then() handlers, each returning a new promise.
Your code looked like it used await but it didn't
I added the example of how to fix your code with await because you wrote your code as if this:
var info = new Promise(...);
// here the 'info' variable is set to a promise
was really this:
var info = await new Promise(...);
// here the 'info' variable is set to the value
// that the promise eventually resolves to
More info
For more info, see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Node support
For support of that syntax in Node versions, see:
http://node.green/#ES2017-features-async-functions
In places where you don't have native support for async and await you can use Babel:
https://babeljs.io/docs/plugins/transform-async-to-generator/
or with a slightly different syntax a generator based approach like in co or Bluebird coroutines:
https://www.npmjs.com/package/co
http://bluebirdjs.com/docs/api/promise.coroutine.html
In your code, info is a promise. Thus, you don't compare info to anything. To get access to the result in a promise, you use .then() on the promise as in:
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});
In addition, your .catch() handler is "eating" the error after logging it. If you don't rethrow the error or return a rejected promise from a .catch() handler, then the error is considered "handled" and the promise state changes to fulfilled.
So, you can do this:
let info = new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).catch(err => {
console.log("error: " + err);
// rethrow error so promise stays rejected
throw err;
});
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});

Promise.all find which promise rejected

In my code, I am using Promise.all() to run code asynchronously once some promises have all fulfilled. Sometimes, one promise will fail, and I'm not sure why. I would like to know which promise is failing. Passing a callback as a second parameter to the .then method does not help much, as I know that a promise is rejecting but not which promise is rejecting.
A stack trace does not help either, as the first item is the Promise.all()'s error handler. A line number from the Error object passed to the first parameter of the second function passed to the try function of the Promise.all() is simply the line number of the line where I log the line number.
Does anybody know of a way to find out which promise is rejecting?
You can use an onreject handler on each promise:
Promise.all(promises.map((promise, i) =>
promise.catch(err => {
err.index = i;
throw err;
});
)).then(results => {
console.log("everything worked fine, I got ", results);
}, err => {
console.error("promise No "+err.index+" failed with ", err);
});
In general, every rejection reason should contain enough information to identify the issue that you need to handle (or log).
this wrapper will wait for and return every result and/or rejection
the returned array will be objects
{ // this one resolved
ok: true,
value: 'original resolved value'
},
{ // this one rejected
ok: false,
error: 'original rejected value'
},
{ // this one resolved
ok: true,
value: 'original resolved value'
},
// etc etc
One caveat: this will wait for ALL promises to resolve or reject, not reject as soon as the first rejection occurs
let allresults = function(arr) {
return Promise.all(arr.map(item => (typeof item.then == 'function' ? item.then : Promsie.resolve(item))(value => ({value, ok:true}), error => ({error, ok:false}))));
}
allresults(arrayOfPromises)
.then(results => {
results.forEach(result => {
if(result.ok) {
//good
doThingsWith(result.value);
} else {
// bad
reportError(result.error);
}
});
});

Categories

Resources