I am using the Node request library which can be found at the following link
https://github.com/request/request
I have a number of functions which look like the following
function doRequest() {
return new Promise(function(resolve,reject) {
request('some-url', function(error,response,body) {
if (!error && response.statusCode === 200) {
resolve(body)
}
});
});
}
I then call these functions like so
doRequest()
.then(function(response){
console.log(response);
})
My question is, is there a way of writing my doRequest function without having to create a new Promise? I feel like it is awkward looking and could possibly be an anti-pattern? Sort of how in AngularJS you often see people using
$q.defer()
when making http calls, when the http call already returns a promise.
Any advice would be great.
If you wanted to make Promises manually based on the results of the request() method then that is the right way to do it (although a reject() call on error is also required).
However that request library already appears to support the Bluebird Promise library's Promisify function, which can automatically wrap those functions into ones that return Promises.
Related
I am using request module in my NodeJS application, for making server-to-server API calls. I am making the API call like this:
request(options, function (error, response, body) {
if( error ){
// return error response
}
// return success response here
});
For some reason, I need to not use this asynchronous way of making call, but do it synchronously. So, is there any way to make this call in synchronous manner. I tried and found some other modules for this, but I need to use this same module.
Thanks
No you cannot not. Request will return you promise and you have to handle it somewhere using .then() or calling the function with async/await pattern.
Because an HTTP request is asynchronous by nature, you cannot do it synchronously. However, you can use ES6+ Promises and async/await like so:
// First, encapsulate into a Promise
const doRequest = () => new Promise((resolve, reject) => request(options, function (error, response, body) {
if( error ){
reject(error)
}
resolve(response)
});
// And then, use async/await
const x = 1 + 1
const response = await myRequest()
console.log(response)
More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
As indicated by #Errorname, promises are probably what you are looking for. Instead of writing the code by hand, you could also use the package request-promise: https://www.npmjs.com/package/request-promise
If you want a strongly-typed, synchronous client, you can try out ts-sync-request.
NPM: https://www.npmjs.com/package/ts-sync-request
This library is a wrapper around sync-request.
You can attach a header & make a request like below:
import { SyncRequestClient } from 'ts-sync-request/dist'
let url = "http://someurl.com";
let response = new SyncRequestClient()
.addHeader("content-type", "application/x-www-form-urlencoded")
.post<string, MyResponseModel>(url, "city=Dubai");
I have a Meteor.method() that server side returns a promise from oracledb. Client side I have:
Meteor.call('myMethod', (error, result) => {
result.then() // err -> no .then() method?,
});
So what is result? It does not have a .then() method, so it is not a promise?
Meteor does not "send" the promise to the client.
The server returns a result value to the client (which triggers the callback) once the promise is resolved (or rejected) on the server, and not at the moment the promise is returned from the method itself (unless it is already settled when returned).
You can also use async/await to simplify the code.
Here is a blog post with more details about the using asynchronous code in methods.
Note:
The value sent from the server is serialized using EJSON. Object methods, getters, etc. are stripped from it, unless you create a custom serializer. In some cases, serialization might even fail (I think it happened with certain moment objects) and result in undefined being returned.
Meteor is not using promises by default, however, you can wrap your Meteor.calls into a promise function as below
const callWithPromise = (method, myParameters) => {
return new Promise((resolve, reject) => {
Meteor.call(method, myParameters, (err, res) => {
if (err) reject('Something went wrong');
resolve(res);
});
});
}
(async function() {
const myValue1 = await callWithPromise('myMethod1', someParameters);
const myValue2 = await callWithPromise('myMethod2', myValue1);
})();
Sample code has copied from Meteor forum.
Also, this topic gives you a better insight in taking advantages of Aysnc/Await syntax or Promises in Meteor calls.
I always read that using Promises with async.js is not a good idea. I would like to understand why.
I'm working in a project that i'm using async.eachLimit to control the limit of async operation in files, and Promises to return the result after i finish all the async operations. Example:
const maxOfAsync = process.env.maxOfAsync || 500;
return new Promise((resolve, reject) => {
async.eachLimit(arrayOfFiles, maxOfAsync, (file, callback) => {
callExternalLib(file).then((data) => {
file.data = data;
callback();
}).catch((error) => {
callback(error);
});
}, (error) {
if (error) return reject(error);
resolve(arrayOfFiles);
});
});
If i should not use both together, how to achieve the same result? Let's forget about async/await for a minute and return to the days that only Promises and async.js exists. What could i do?
Thanks.
Bluebird's Promise.map allows you to step over an Iterable and set a concurrency.
return Promise.map(arrayOfFiles, file => {
return callExternalLib(file).then((data) => {
file.data = data;
return file;
}
}, { concurrency: maxOfAsync })
Promise.map will resolve a new array of values once all promises are resolved. It's not a requirement to mutate an existing array like the original code and the example above is doing.
I think that combining async callback syntax with promise syntax can confusing code. I don't think there's anything inherently wrong with it. If my code is all using promises and I introduce a library that uses callbacks, I would usually wrap that library with promises to keep my code clean.
Async.js is kind of "meh" when you want to use promises. It's good at what is does but is clearly a library that was built to ease the use of callbacks and that was later upgraded to try to work with promises. It even tries to make some auto-magic decompilation of the code to try to know if a function should be handled like an async function returning a promise or a non-async function using a callback (and, like all libraries making decompilation, it can and will fail if you compile your code with Babel or similar tools).
I recently published a library which is an alternative to async.js and that was precisely made to use only Promises (and async/await), thus making a fully-consistant library to work using those newer tools.
The result is named modern-async and is here: https://nicolas-van.github.io/modern-async/
So.. I am new to this Javascript and using JSON. I am developing a webpage which in this case needs comments, then the current username.
In order to develop this, I tried to create a function that returns the username using the getJSON() method, but obviously that would not work. What I came up with instead was using nested getJSON calls.
Something like this:
$.getJSON(getCommentsURL, function(jsonComments){
$.getJSON(getUsernameURL, function(username){
jsonComments[0].deleteButton = (jsonComments[0].username === username)
// programming logic
});
});
Mainly, the reason why I need both information is described in Row 3 of the code sample.
The question I have is, is this implementation acceptable conventionally? It does work, but there might be a more appropriate way to do this implementation. The reason I care about conventions, and appropriate ways to do this, is not only for my own knowledge, but because it is a school assignment that requires the code to be clean and correct (not only that it works).
Very grateful for any answers.
This is a good use case for using jQuery's answer to Promise.all - $.when.
var commentsPromise = $.getJSON(getCommentsURL);
var usernamePromise = $.getJSON(getUsernameURL);
// when both requests complete
$.when(commentsPromise, usernamePromise).then(function(jsonComments, username) {
jsonComments[0].deleteButton = (jsonComments[0].username === username)
// programming logic
});
The approach at Question should return expected result, you alternatively could use .then(). You could also include .fail() or .catch() chained to .then() to handle errors. Note return statement within .then()
$.getJSON(getCommentsURL)
.then(function(jsonComments) {
return $.getJSON(getUsernameURL)
.then(function(username){
jsonComments[0]
.deleteButton = (jsonComments[0].username === username)
// programming logic
});
})
.fail(function(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})
I am creating a node module and I want to be able to support both node callback and Promise APIs. The library that I hear the best things about (mainly that is it the fastest) is bluebird. So after reading some docs and looking at some other libraries that are using bluebird, I thought this would be the cleanest way to get a method to support both node callback and Promise APIs:
this.isAllowed = function(role, resource, permission, callback) {
var isAllowedAsync = bluebird.promisify(isAllowed);
return isAllowedAsync(role, resource, permission).nodeify(callback);
};
However with this code, the callback is never executed. After some more research, I tried this:
this.isAllowed = function(role, resource, permission, callback) {
return new bluebird(function (resolve, reject) {
resolve(isAllowed(role, resource, permission));
}).nodeify(callback);
};
With that code, both the node callback and Promise API works.
For reference, this is the isAllowed method:
var isAllowed = function(role, resource, permission) {
if(!lists[role] || !lists[role][resource]) {
return false;
}
return lists[role][resource].indexOf(permission) !== -1;
};
Am I doing something wrong in the first code example or is the second example the real way of getting what I am looking for?
Your specific problem makes no sense (see my comment) so I'll just be generic. There are 2 ways to expose a dual promise/callback API.
First way is to have the same function support promises and callbacks at the same time, by returning a promise if callback parameter is not passed or using the callback if it is passed.
However this is hard to implement and can have some nasty problems when some arguments are optional.
To implement it, you do exactly the same thing as you would with a 100% promise function except you add a .nodeify at the end of the returned chain.
// Note however this doesn't work if some arguments before
// `callback` are optional
function dualApi(..., callback) {
// acting as if you would never support callbacks at all
return getPromise()
.then(...)
.then(...)
.then(...)
// .nodeify at the end of the chain, NOWHERE else
.nodeify(callback)
}
The second way is to define a normal callback api, and then just call promisifyAll. This is very easy to implement, in fact there is almost no reason to do it at all because the user can so easily promisify the module themselves if they use bluebird.