This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 6 years ago.
I am using Angular2 for my application and I have to consume Amazon S3 javascript sdk for browser.
I have the following function:
getBuckets() {
var s3 = this.getS3();
var params = {};
s3.listBuckets(params, function(err, response) {
if (err) {
// What to return?
}
else {
// What to return?
}
})
}
s3.listBuckets is the javascript API from Amazon for S3. It is expecting a call back function. But the caller of getBuckets is expecting a Promise. How should I change the above getBuckets(), such that the caller of getBuckets(), will look like:
getBuckets().then(
...
)
Thanks in advance.
If you are using TypeScript you can do something like this to return a promise. I can imagine it would be around the same in the JavaScript style:
getBuckets() {
return new Promise(function (resolve, reject) {
var s3 = this.getS3();
var params = {};
s3.listBuckets(params, function(err, response) {
if (err) {
reject(err);
}
else {
resolve(response);
}
})
})
}
The AWS SDK for JavaScript has supported promises since version 2.3.0 released March 31st. Here's the annoucement.
I suggest you update to the latest SDK version if you are using something earlier than 2.3.0, and then use promises instead of callbacks.
You can use $q, documentatie here: https://docs.angularjs.org/api/ng/service/$q
That would look something like this:
getBuckets() {
var deferred = $q.defer();
var s3 = this.getS3();
var params = {};
s3.listBuckets(params, function(err, response) {
if (err) {
deferred.reject(err);
}
else {
deferred.resolve(response);
}
})
return deferred.promise;
}
you can create your own promise like this:
var myPromiseFunction = function(iserr){
var deferred = $q.defer();
var myreturnvalue = 'somevalue';
if(iserr === true){
deferred.reject('some error');
}else{
deferred.resolve(myreturnvalue);
}
return deferred.promise;
}
And call it like this:
var throwerror = false;
//or var throwerror = true; if you want to create an error
myPromiseFunction(throwerror).then(function(res){
console.log(res);
}).catch(function(err){
console.log(err);
})
This way you can create promises (they don't even have to be async but it would not have any purpose for non-async operations.
Related
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
I am using this query to select all records from the products table and I want to store them inside an object variable which later I can use it for other purposes, so I tried this
var SelectQuery = "Select * FROM `products`";
var ProductDetails = {};
conn.query(SelectQuery, function (err, result) {
if(err) {
console.log(err);
} else {
ProductDetails = result;
}
});
console.log(ProductDetails);
But in Console I get this {}.
(Thanks to user jfriend00 for pointing out a major oversight in my original answer)
If conn.query is returning a promise then you could make this work in the manner you are describing by using async/await:
async function getProducts() {
var SelectQuery = "Select * FROM `products`";
var ProductDetails = {};
await conn.query(SelectQuery, function(err, result) {
if (err) {
console.log(err);
} else {
ProductDetails = result;
}
});
console.log(ProductDetails);
}
But note this only works if your conn.query returns a promise. Also, it is a newer ES feature, so you may need to transpile it depending on your node version. Also, note that the function this takes place in will need to be wrapped with async.
Otherwise, the other candidates to leverage for handling asynchronicity are callback functions and Promises.
If conn.query does not return a promise, you could write your own query implementation that would return a promise so you could leverage async/await:
function asyncQuery(sqlQuery) {
return new Promise((resolve, reject) => {
conn.query(SelectQuery, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
})
})
}
Then the original function could be rewritten as:
async function getProducts() {
var SelectQuery = "Select * FROM `products`";
var ProductDetails = await asyncQuery(SelectQuery);
console.log(ProductDetails);
}
I have two files in my application,
DesignFactory.js:
var fs = require('fs');
var dotenv = require('dotenv');
dotenv.load();
var designtokenfile = require ('./designtokenfile');
var designtokendb = require ('./designtokendb');
var TYPE=process.env.TYPE;
var DesignFactory={};
DesignFactory.storeDesign = function(TYPE) {
if (TYPE == 'file') {
var data=design.designtokenfile.load();
console.log(data);
} else if (TYPE == 'db') {
return designtokendb;
}
};
module.exports.design=DesignFactory;
now, I have another designtokenfile.js file,
designtokenfile.js:
var fs = require('fs');
var load = function() {
fs.readFile('output.txt', 'utf8', function (err,data) {
return data;
if (err) {
return console.log(err);
}
});
};
module.exports.load=load;
So my problem is am not able get data returned from load method. when I print data inside storeDesign method returned from load function, it displays undefined.
but I want contents of output.txt inside storeDesign method.
Please help me.
Instead of:
var load = function() {
fs.readFile('output.txt', 'utf8', function (err, data) {
return data;
if (err) {
return console.log(err);
}
});
};
which has no way of working because the if after the return would never be reached, use this:
var load = function(cb) {
fs.readFile('output.txt', 'utf8', function (err,data) {
if (err) {
console.log(err);
return cb(err);
}
cb(null, data);
});
};
and use it like this:
load((err, data) => {
if (err) {
// handle error
} else {
// handle success
}
});
Or use this:
var load = function(cb) {
return new Promise(resolve, reject) {
fs.readFile('output.txt', 'utf8', function (err, data) {
if (err) {
console.log(err);
reject(err);
}
resolve(data);
});
});
};
and use it like this:
load().then(data => {
// handle success
}).catch(err => {
// handle error
});
In other words, you cannot return a value from a callback to asynchronous function. Your function either needs to tak a callback or return a promise.
You need to reed more about asynchronous nature of Node, about promises and callbacks. There are a lot of questions and answers on Stack Overflow that I can recommend:
promise call separate from promise-resolution
Q Promise delay
Return Promise result instead of Promise
Exporting module from promise result
What is wrong with promise resolving?
Return value in function from a promise block
How can i return status inside the promise?
Should I refrain from handling Promise rejection asynchronously?
Is the deferred/promise concept in JavaScript a new one or is it a traditional part of functional programming?
How can I chain these functions together with promises?
Promise.all in JavaScript: How to get resolve value for all promises?
Why Promise.all is undefined
function will return null from javascript post/get
Use cancel() inside a then-chain created by promisifyAll
Why is it possible to pass in a non-function parameter to Promise.then() without causing an error?
Implement promises pattern
Promises and performance
Trouble scraping two URLs with promises
http.request not returning data even after specifying return on the 'end' event
async.each not iterating when using promises
jQuery jqXHR - cancel chained calls, trigger error chain
Correct way of handling promisses and server response
Return a value from a function call before completing all operations within the function itself?
Resolving a setTimeout inside API endpoint
Async wait for a function
JavaScript function that returns AJAX call data
try/catch blocks with async/await
jQuery Deferred not calling the resolve/done callbacks in order
Returning data from ajax results in strange object
javascript - Why is there a spec for sync and async modules?
Return data after ajax call success
fs.readFile ist asynchrone so you need to pass a callback function or use fs.readFileSync
You are getting undefined because of asynchronous nature.. Try for the following code:
var fs = require('fs');
var load = function(callback) {
fs.readFile('output.txt', 'utf8', function (err,data) {
//return data;
callback(null, data);
if (err) {
callback("error", null);
}
});
};
module.exports.load=load;
var fs = require('fs');
var dotenv = require('dotenv');
dotenv.load();
var designtokenfile = require ('./designtokenfile');
var designtokendb = require ('./designtokendb');
var TYPE=process.env.TYPE;
var DesignFactory={};
DesignFactory.storeDesign = function(TYPE) {
if (TYPE == 'file') {
var data=design.designtokenfile.load(function(err, res){
if(err){
} else {
console.log(data);
}
});
} else if (TYPE == 'db') {
return designtokendb;
}
};
module.exports.design=DesignFactory;
This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 6 years ago.
I have this node js app working with several callback functions which I am trying to promisify to no avail.
Its getting to the point where I dont know if it is even possible. If you can help me promisify the code below I'll probably be able to do the rest of it:
var i2c_htu21d = require('htu21d-i2c');
var htu21df = new i2c_htu21d();
htu21df.readTemperature(function (temp) {
console.log('Temperature, C:', temp);
});
Any insight helps!!!
The common pattern is:
<promisified> = function() {
return new Promise(function(resolve, reject) {
<callbackFunction>(function (err, result) {
if (err)
reject(err);
else
resolve(result);
});
});
}
For your specific example (to which you might want to add error handling):
readTemperature = function() {
return new Promise(function(resolve) {
htu21df.readTemperature(function (temp) {
resolve(temp);
});
});
}
readTemperature().then(function(temp) {
console.log('Temperature, C:', temp);
});
You need to use bluebird for this.
var bluebird = require('bluebird');
var i2c_htu21d = require('htu21d-i2c');
var htu21df = new i2c_htu21d();
var readTemperature = bluebird.promisify(htu21df.readTemperature);
readTemperature().then((temp) => {console.log('Temperature, C:', temp);});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
var async = require('async');
var square = function (id, callback) {
Business.prototype.getBusinessUser(id,function(userObject){
return callback(userObject);
});
};
async.eachSeries(findBusinessResult, function (businessObject, callback) {
//console.log("results from square");
var result = square(businessObject["id"] , function(result){
console.log(result);
});
callback(); // Alternatively: callback(new Error());
}, function (err,results) {
if (err) { throw err; }
console.log('Well done :-)!');
console.log(results);
});
Why does the result always become undefined: any help please.
async is reserved word in ES7 and might give you problem later, when it's implemented.
What you might want to consider is actually using async/await togheter with babel.
Some browser is starting to implement it already
var square = id =>
new Promise(rs =>
Business.prototype.getBusinessUser(id, rs)
)
async search() {
for (let businessObject of findBusinessResult) {
let result = await square(businessObject.id)
console.log(result)
}
}
I hope this will be a game changer solution for most ppl. This is making ASYC java callback into somthing which look like sync with effiecent callback handling. Its my three days of challange. [Callbacks][1] are indeed a a major challage in javacript and here is how to solve issue using promises .
install bluebird
npm install bluebird --save
//inyour code
var Promise = require('bluebird'); //yeah awsome bird indeed :)
function extendBusinessObjectPromise(id,element) {
return new Promise(function(resolve, reject) {
Business.prototype.getBusinessUser( id ,function(userObject){
var extend = require('util')._extend;
mergedJson = userObject;
elements = element;
extend({},elements);
extend(elements,mergedJson);
global.businesssWithUsers.push(elements); //sahred object
resolve(global.businesssWithUsers)
})
})
}
//NOW how do you i call the promise result inside a foreach loop and get its value returned as callback result. seem crazy idea :(
Person.prototype.getPersons = function(filter , callback) {
//this my own Bill count since i have one using one user account
global.businesssWithUsers = [];
models.PersonModel.findAll(filter_combined).then(function (findBusinessResult) {
global.businesssWithUsers = []
var extend = require('util')._extend;
var mergedJsonArray = [];
if (findBusinessResult==null) {
return callback(false,"no result found");
}
var promiseBusinessResult = null; //promise reslover :)
var findBusinessResult =JSON.parse(JSON.stringify(findBusinessResult));
findBusinessResult.forEach(function(eachElement) {
var id = element["userId"];
promiseBusinessResult = extendBusinessObjectPromise(id,element);
});
promiseBusinessResult.done(function(result){
callback(true,result); //pass the result to main function
});
}).catch(function (err) {
log.error(err["errors"][0]["message"])
callback(false,err["errors"][0]["message"])
return
})
}
Success at last. Cheers!
I am seeking for an architecture advice. Using Bluebird Promises in a MEAN environment (talking node.js server-side here), I intend to make many concurrent API calls, aggregate all results and respond to client. Example (pseudo-)code:
exports.getAllData = function(searchquery, cb) {
var results;
wrapper1.getResultsFromAPI1(searchquery, function(err,data){
results += data;
});
wrapper2.getResultsFromAPI2(searchquery, function(err,data){
results += data;
});
wrapper3.getResultsFromDataBase(searchquery, function(err,data){
results += data;
});
if (AllRequests done){
cb(null,results);
}
}
Now I don't know how I can make sure to:
Fire all requests concurrently (NOT sequentially to reduce
response time)
Respond to client once I got responses from ALL API requests
In case of one API request to fail for whatever reason, not having the entire promise chain to be rejected, thus "loosing" the other API response data.
I checked on Bluebird Promise website for appropriate collections, but none seems to fully meet the requirements listed above. Any suggestions?
One way of doing this would be using reflect calls.
var Promise= require('bluebird');
Promise.props({
"wrapper1": someasync(1).reflect(),
"wrapper2": someasync(0).reflect(),
"wrapper3": someasync(1).reflect()
})
.then(function(results) {
Object.keys(results).forEach(function(key) {
if (results[key].isRejected()) {
console.log(key + " failed.", results[key].reason());
} else {
console.log(key + " successed", results[key].value());
}
});
});
function someasync(t) {
if (t===0) return Promise.reject('some err');
else return Promise.resolve(true);
}
Which results in the following:
wrapper1 successed true
wrapper2 failed. some err
wrapper3 successed true
var Promise= require('bluebird');
var chain = require('lodash').chain;
function rejectedPromise(settledPromise) {
return settledPromise.isRejected();
}
function extractResponse(fulfilledPromise) {
return fulfilledPromise.value();
}
Promise.settle([
asyncCall(),
asyncCall(),
asyncCall()
])
.then(function retrieveSuccessfulResponses(settledPromises) {
return chain(settledPromises)
.reject(rejectedPromise)
.map(extractResponse)
});
If you want, you can manually promisify your API methods, e.g:
var p1 = new Promise(function(resolve, reject) {
wrapper1.getResultsFromAPI1(searchquery, function(err, data) {
if (err) reject(err);
else resove(data);
});
});
But since you're using the BlueBird library, then you can use Promise.promisify, so you can avoid the boilerplate code of wrapping the methods into promises. E.g:
var getResultsFromAPI = Promise.promisify(wrapper1.getResultsFromAPI1);
var p1 = getResultsFromAPI(searchquery);
And if you want to promisify all the methods of an API, you can use Promise.promisifyAll. E.g:
var wrapper1 = Promise.promisifyAll(require('my-api'));
// then, all the wrapper1 methods are already wrapped into a Promise
var p1 = wrapper1.getResultsFromAPI1(searchquery);
So, after turning all your methods into Promises, you can use the Promise.settle to achieve what you want: See what promises were fulfilled and what of them were rejected:
exports.getAllData = function(searchquery, cb) {
/* Don't forget to promisify all the API methods firstly */
var results;
var p1 = wrapper1.getResultsFromAPI1(searchquery);
var p2 = wrapper2.getResultsFromAPI2(searchquery);
var p3 = wrapper3.getResultsFromDataBase(searchquery);
Promise.settle([p1, p2, p3]).then(function(arr) {
arr.forEach(function(res, index) {
if (res.isFulfilled()) { // check if the Promise was fulfilled
results += res.value(); // the Promise's return value
}
else if (res.isRejected()) { // check if the Promise was rejected
console.log(res.reason()); // do something with the error
}
});
cb(null, results);
});
}