var promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
we can use "try-catch" to throw error
// mothod 2
var promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
we also can use "reject" to throw error.
what's difference between them?
Exceptions thrown from asynchronous functions cannot be handled with try-catch block.
Promises are chain-able; prevents us from nesting code that affects readability.
There is no effective difference. In both cases, you're calling reject() with an error.
The following are also equivalent to what you have there:
var promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
var promise = Promise.reject(new Error('test'));
var promise = Promise.resolve().then(function () { throw new Error('test'); });
Related
Im adding a duplicate to a mysql table and I want to handle elicited ER_DUP_ENTRY error comming back with a Try/Catch block but its just crashing anyway , is there any possible way to handle error and stop application from crashing using a try/catch block?
async function init() {
try {
connection.query(
'SOME INSERT QUERY',
(err, result, feilds) => {
if (err) throw err
console.log(result);
}
);
} catch (e) {
console.log(e);
}
}
init();
The node mysql-library does not support promises out of the box, which means query does not return a promise which you can await. So you can either wrap the query function in a promise yourself:
async function init() {
try {
const duplicateResult = await new Promise((resolve, reject) => {
connection.query(
'SOME INSERT QUERY',
(err, result, fields) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
} catch (e) {
console.log(e);
}
}
or use util.promisify as Always Learning posted alternatively.
The problem is that connection.query returns undefined right away. Your catch is not involved because the call ends before the work is done and will call your callback function later. An exception that occurs during your callback is too late. You try/catch block has already completed.
You can use promisify to wait on it like this though:
const util = require("util");
function init() {
const queryPromise = util.promisify(connection.query);
return queryPromise('SOME INSERT QUERY')
.catch(e => {
console.log("It failed", e);
});
}
init().then(result => {
if (result) console.log("It worked", result);
else console.log("Aww, it didn't work");
});
I'm trying to use d3.json() inside of a function to return data Spotify's API given an artist ID (such as 5K4W6rqBFWDnAN6FQUkS6x), but I can't figure out how to effectively return the data. The function looks like
// Get artist's related artist's information
function relatedArtists(id){
var jsonPromise = new Promise(function(resolve, reject) {
// Async JSON request
d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data){
if(error) reject(error);
resolve(data.artists);
});
});
jsonPromise.then(function(success) {
console.log(success);
//return(success) //doesn't work
});
jsonPromise.catch(function(error){
console.error(error);
});
}
I've tried creating a variable within the function and then modifying it
function relatedArtists(id){
var testVar = 'hello';
var jsonPromise = new Promise(...{
// Async JSON request
d3.json(...)
});
jsonPromise.then(function(success) {
testVar = success;
});
return(testVar);
}
But testVar remains 'hello', despite my best efforts. I've done some reading about scope and promises, but am happy to do more if there's some core mechanic of either that I'm not understanding. Thanks for reading!
The response will never be available in your calling code due to asynchronous nature of requests. You can use Promises (as supposed by Alexander T. and you, good choice in many cases!) but d3.queue does a good job, too. In my snippet you can see how to run code with the results of multiple requests.
function buildRelatedArtistUri(id) {
return 'https://api.spotify.com/v1/artists/' + id + '/related-artists';
}
d3.queue()
.defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
.await(function(error, data) {
// data and data.artists are available in this function‘s scope only
console.log(data.artists);
});
d3.queue()
.defer(d3.json, buildRelatedArtistUri('5K4W6rqBFWDnAN6FQUkS6x'))
.defer(d3.json, buildRelatedArtistUri('3nFkdlSjzX9mRTtwJOzDYB'))
.await(function(error, data1, data2) {
// this function will be called once both functions have finished
console.log(data1.artists, data2.artists);
});
<script src="https://d3js.org/d3.v4.min.js"></script>
You can return Promise and use relatedArtists function like so
function relatedArtists(id) {
return new Promise(function(resolve, reject) {
d3.json('https://api.spotify.com/v1/artists/' + id + '/related-artists', function(error, data) {
if (error) {
reject(error);
} else {
resolve(data.artists);
}
});
});
}
relatedArtists('5K4W6rqBFWDnAN6FQUkS6x')
.then(function (data) {
console.log(data);
})
.catch(function (error) {
console.log(error);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
In this case, you can not assign the value to testVar, because d3.json is the asynchronous method and that means that d3.json can be done after code execution.
What is the best way to handle this scenario. I am in a controlled environment and I don't want to crash.
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
When throwing from within the setTimeout we will always get:
$ node bluebird.js
c:\blp\rplus\bbcode\scratchboard\bluebird.js:6
throw new Error("AJAJAJA");
^
Error: AJAJAJA
at null._onTimeout (c:\blp\rplus\bbcode\scratchboard\bluebird.js:6:23)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If the throw occurs before the setTimeout then bluebirds catch will pick it up:
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
throw new Error("Oh no!");
setTimeout(function(){
console.log("hihihihi")
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
Results in:
$ node bluebird.js
Error [Error: Oh no!]
Which is great - but how would one handle a rogue async callback of this nature in node or the browser.
Promises are not domains, they will not catch exceptions from asynchronous callbacks. You just can't do that.
Promises do however catch exceptions that are thrown from within a then / catch / Promise constructor callback. So use
function getPromise(){
return new Promise(function(done, reject){
setTimeout(done, 500);
}).then(function() {
console.log("hihihihi");
throw new Error("Oh no!");
});
}
(or just Promise.delay) to get the desired behaviour. Never throw in custom (non-promise) async callbacks, always reject the surrounding promise. Use try-catch if it really needs to be.
After dealing with the same scenario and needs you are describing, i've discovered zone.js , an amazing javascript library , used in multiple frameworks (Angular is one of them), that allows us to handle those scenarios in a very elegant way.
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs
Using your example code :
import 'zone.js'
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
Zone.current
.fork({
name: 'your-zone-name',
onHandleError: function(parent, current, target, error) {
// handle the error
console.log(error.message) // --> 'AJAJAJA'
// and return false to prevent it to be re-thrown
return false
}
})
.runGuarded(async () => {
await getPromise()
})
Thank #Bergi. Now i know promise does not catch error in async callback. Here is my 3 examples i have tested.
Note: After call reject, function will continue running.
Example 1: reject, then throw error in promise constructor callback
Example 2: reject, then throw error in setTimeout async callback
Example 3: reject, then return in setTimeout async callback to avoid crashing
// Caught
// only error 1 is sent
// error 2 is reached but not send reject again
new Promise((resolve, reject) => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Nothing happen
})
.then(() => {})
.catch(err => {
console.log("Error", err);
});
// Uncaught
// error due to throw new Error() in setTimeout async callback
// solution: return after reject
new Promise((resolve, reject) => {
setTimeout(() => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Did run and cause Uncaught error
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});
// Caught
// Only error 1 is sent
// error 2 cannot be reached but can cause potential uncaught error if err = null
new Promise((resolve, reject) => {
setTimeout(() => {
const err = "error 1";
if (err) {
reject(err); // Send reject
console.log("Continue"); // Did print
return;
}
throw new Error("error 2"); // Potential Uncaught error if err = null
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});
I have a scenario where the webservice needs to check for existense of key in redis if present give it as a response else get it from mysql, store in redis and then give it as response.
So i am using promises concept where first time when i call return new Set_Data(); it doesn't go to next then block it just stays idle. But next time since data already exists the return new Set_Data();
is not executed which is correct.
But why is that i am getting problem for first time when i call return new Set_Data(); which is not going for next then block.
Below is my code
constants.js file
var Promise = require('bluebird');
module.exports =
{
getRedisConnection: function ()
{
return require("redis").createClient(6379, 'path', { auth_pass: 'key' });
},
getMySqlConnection: function ()
{
var conObj = { host: "localhost", user: "root", password: "", database: "deccan" };
var connection = require("mysql").createConnection(conObj);
return new Promise(function (resolve, reject)
{
connection.connect(function (error)
{
if (error)
reject(error);
else
resolve(connection);
});
});
}
};
webservicefile.js
var Promise = require('bluebird');
var express = require('express');
var router = express.Router();
var constants = require("../constants");
function getSettings(request, response)
{
var client = constants.getRedisConnection();
get_Data();
function get_Data()
{
return new Promise(function (resolve, reject)
{
client.get("url", function (error, reply)
{
if (error)
reject(error);
else
{
if (reply == null)
resolve(); // Key not present so create
else
resolve(reply);
}
});
}).
catch(function (e)
{
console.log("Error at : " + new Date().toString() + ", => " + e);
}).
then(function (urlResult)
{
return new Promise(function (resolve, reject)
{
if (urlResult == undefined || urlResult == null)
{
return new Set_Data();
}
else
{
client.quit();
return resolve(urlResult);
}
});
}).
then(function (urlResult)
{
if (urlResult)
response.status(200).send({ url : urlResult });
else
response.status(500).send();
})
}
function Set_Data()
{
constants.getMySqlConnection().then(function (connection)
{
return new Promise(function (resolve, reject)
{
connection.query("select url from table where id = 1", function (error, results)
{
connection.end();
if (error)
reject(error);
else
resolve(results);
});
});
}).
then(function (url)
{
return new Promise(function (resolve, reject)
{
client.set('url', url, function (err, reply)
{
if (err)
reject(err);
else
resolve(url);
});
});
});
}
}
A couple of changes should do the trick, first Set_Data() doesn't return a promise like you think it does, add a return:
function Set_Data() {
return constants.getMySqlConnection().then(function (connection).then()
// ...
}
Inside this callback, you don't have a resolve() in the if so the promise is never resolved, returning something doesn't resolve:
// your code
then(function (urlResult) {
return new Promise(function (resolve, reject) {
if (urlResult == undefined || urlResult == null) {
return new Set_Data();
} else {
client.quit();
return resolve(urlResult);
}
});
}).
Return Set_Data() which is now a promise or the url:
then(function (urlResult) {
if (urlResult == undefined || urlResult == null) {
return new Set_Data();
} else {
client.quit();
return urlResult;
}
}).
On a side note, don't format your js code like C#, { shouldn't be on a new line.
You can return new Set_Data() directly if no urlResult, or return urlResult otherwise - inside then any (non Promise) value returned is a resolved Promise - so the .then chain will continue as required
function get_Data() {
// ...
.then(function (urlResult) {
// you don't need a "new Promise" here
if (urlResult == undefined || urlResult == null) {
return new Set_Data();
} else {
client.quit();
return urlResult;
}
})
// ...
}
One thing I noticed in your code is a .catch in the middle of your .then chain which will effectively turn an error into a fulfilled promise - not sure if that's the behaviour you are looking for. Something else to look out for
Some time ago I decided to switch from PHP to node. In my first projects I didn't want to use any ORM since I thought that I didn't need to complicate my life so much learning another thing (at the moment I was learning node and angular) therefor I decided to use mysql package without anything else. It is important to say that I have some complex queries and I didn't want to learn from sctratch how to make them work using one of the 9000 ORM node have, This is what I've been doing so far:
thing.service.js
Thing.list = function (done) {
db.query("SELECT * FROM thing...",function (err,data) {
if (err) {
done(err)
} else {
done(null,data);
}
});
};
module.exports = Thing;
thing.controler.js
Thing = require('thing.service.js');
Thing.list(function (err,data) {
if (err) {
res.status(500).send('Error D:');
} else {
res.json(data);
}
});
how can I promisify this kind of functions using bluebird ? I've already tried but .... here I am asking for help. This is what I tried
var Thing = Promise.promisifyAll(require('./models/thing.service.js'));
Thing.list().then(function(){})
I have done this way and it is working fine.
const connection = mysql.createConnection({.....});
global.db = Bluebird.promisifyAll(connection);
db.queryAsync("SELECT * FROM users").then(function(rows){
console.log(rows);});
I have never had much luck with promisifyAll and IMO I prefer to handle my internal checks manually. Here is an example of how I would approach this:
//ThingModule
var Promises = require('bluebird');
Things.list = function(params) {
return new Promises(function(resolve, reject) {
db.query('SELECT * FROM thing...', function(err, data) {
return (err ? reject(err) : resolve(data));
});
});
}
//usage
var thinger = require('ThingModule');
thinger.list().then(function(data) {
//do something with data
})
.error(function(err) {
console.error(err);
})
You can also create a function that fires SQL like this :-
function sqlGun(query, obj, callback) {
mySQLconnection.query(query, obj, function(err, rows, fields) {
if (err) {
console.log('Error ==>', err);
// throw err;
return (err, null);
}
console.log(query)
if (rows.length) {
return callback(null, rows);
} else {
return callback(null, [])
}
});
}
Where mySQLconnection is the connection object you get after mysql.createConnection({}).
After that, you can promisify the function and use the promise like below :-
var promisified = Promise.promisify(sqlGun);
promisified(query, {}).then( function() {} );