I'm using a promise-based package (Axios) for making HTTP requests. So, I have a code like this:
axios.all(/*many generated requests*/).then((res) => {
//success handler
}).catch((err) => {
//error handler
});
I want to write a simple wrapper which generates and sends all the requests, but still has the same syntax. It will make the code above look like:
manyReqsWrapper(args).then((res) => {
//success handler
}).catch((err) => {
//error handler
});
How can I do this?
Promises are simple values and can be returned from functions like everything else. You seem to be looking for
function mayReqsWrapper(args) {
return axios.all(/* whatever you need */);
}
Related
I'm attempting to write some unit tests for API endpoints, and decided on JavaScript Express w/ Supertest. I've got the basic downs, but running into issues checking the response for a specific field. I want to parse the body and check if an expected field returns and has the correct value. Most everything I've seen online uses this method, but when I try it always passes, even when I enter values I know don't exist in the JSON. Any advice? Here is my code snippet:
describe('GET category', function () {
it('response w/ only injury returned', function () {
request('endpoint')
.get('path')
.set('header', 'token')
.expect(200)
.then(response => {
console.assert(response.body, "Baseball")
})
})
});
I have also tried changing the .then to .expect, with same results. If I do response.body.specificFieldinBody I get similar results. Any help?
You can do with your way - use .then syntax, but I think use Supertest assertion syntax will be good.
This mean, use response.body.should.have.property("Baseball"); instead of console.assert(response.body, "Baseball") (Baseball is your special field).
Or, My suggestion is creating a re-use code: Put a assertion callback function to a next expects section.
const isIncludeField = function (fieldName) {
return function (res) {
res.body.should.have.property(fieldName);
};
}
describe('GET category', function () {
it('response w/ only injury returned', function () {
request('endpoint')
.get('path')
.set('header', 'token')
.expect(200)
.expect(isIncludeField('Baseball')) //
.end(done); // call done callback
})
});
Up until now for me the concept of a Node Worker has been one of those things that sounds interesting and I will find out about one day.
Well that day has come and I am asking for some help.
I need to call a web service and then process the data returned. I can call the service with an XMLHttpRequest, but then I have to get useful data out of it.
There is a nice node module that both calls the service and returns the data in a useful form with one call.
I can set up Node worker (in Wakanda) to do this and verify that it works.
My problem is handling the asynchronous call in the proxy.
The call to the node module looks like this:
myModule.getData(param, (err, data) => {
// data is an object containing everything I want.
// if I get data I want to return it to the proxy
// if I get an err I want to return the error to the proxy
});
So my wrapper code looks something like this:
function doSomething(param){
// call proxy with param
// wait for result
// return result
}
This all sounds like something I should know how to do. However I think I am struggling with too many new things and getting myself absolutely confused.
PS: I did try Threadify but couldn't work out how to get the worker to return the error it received.
I would really appreciate any help or pointers here.
If I am correctly understanding your issue, you cannot return a value from a function AFTER an asynchronous call completes. You need to handle the data within the myModule.getData callback.
If you would rather handle it in a calling function (like doSomething), you can use a promise to "return" a value.
function myProxy(param) {
return new Promise((resolve, reject) => {
myModule.getData(param, (err, data) => {
if (!err) { // or however you determine an error occurred.
resolve(data); // if I get data I want to return it to the proxy
} else {
reject(err); // if I get an err I want to return the error to the proxy
}
});
});
}
function doSomething(param){
myProxy(param).then(data => {
// Handle the data here.
}).catch(err => {
// Handle the error here.
});
}
I have a feeling that I'm just trying to fit a square peg into a round hole, but I'm trying to apply some things with Angular2 and Typescript, and I'm banging my head against a wall.
I've written a Javascript module that acts as an API client library to an API I'm consuming. It just packages some convenience things like setting up the correct API keys, switching keys based on certain desired data, etc. It's basically just a convenience library.
Most of the methods follow a pattern where you provide a query term and then execute a callback.
So for example:
API.searchAutocomplete("angular", function(err, data) {
// handle the data/error
});
Inside that method:
searchAutocomplete: function(query, callback) {
// set up request with data payload, url, headers, etc
$.ajax(settings)
.done(function(response) {
// callback with success
})
.fail(function () {
// callback with error
});
}
I'm struggling with trying to understand how to run this function in Typescript in an Angular service with a Promise (square peg round hole). Or should I just pass a callback within the service and treat it like it's Javascript?
My attempt:
public getAutocomplete(query:string): Promise < any > {
return new Promise((resolve, reject) => {
API.searchAutocomplete(query, function (err, result) {
if (err) {
reject(err);
return;
}
resolve(result);
});
});
}
Second, I've been able to load the library into my Angular app but I can't seem to actually make any of the requests. Even if I break in the console and access the library object it doesn't seem to actually make any network requests. Which I really don't understand.
Edit: I've sorted this part out.
When I made my service call return a promise, I had to subscribe to the promise otherwise I wouldn't execute it correctly. I think I still need to understand how to write my service call to return an observable and map the callback response.
As expected, I was trying to do more work than I should have.
This is pretty simple, just return an observable that calls the external library.
public autoCompleteResults(query: string): Observable<string[]> {
return new Observable<string[]>(observer => {
API.searchAutocomplete(query, function (err, result) {
if (err) {
console.log(err);
observer.next([]);
// OR
observer.error(err);
return;
}
observer.next(result);
});
});
}
Im fairly new to RxJs and I would like to understand what the best way is to work with Rx in combination with Promises.
What I want to create is a service in Angular that acts much as an event dispatcher pattern and emits an event once a promise is complete. What I also require is that, if there are no (event) subscribers the observable never gets called. The last thing I want to happen is that any subsequent subscribers to the observable get the same result without triggering another request to the server.
I have managed to implement my own solution here:
// ... CountryService code
var COUNTRIES_LOADED = Rx.Observable
.create(function (observer) {
$http
.get('/countries')
.then(function (res) {
observer.onNext(res);
}, function (err) {
observer.onError(err);
})
.finally(function () {
observer.onCompleted();
});
})
.shareReplay();
Now anytime I subscribe a new "listener" to subject the observable will be pulled. Any new subscribers will get the value cached without touching the server again.
So inside my "consumer" (Angular Directive) I would like to do something like this:
// ... countryInput directive code:
COUNTRIES_LOADED.subscribe(function (response) {
// Fill in countries into scope or ctrl
scope.countries = response.countries;
});
Any future subscribers to the COUNTRIES_LOADED observer MUST NOT trigger an $http request. Likewise, if the directive is never included on the page, $http will never get called.
The solution above works, however I am not aware of the potential drawbacks and memory implications of this approach. Is this a valid solution? Is there a better / more appropriate way to achieve this using RxJs?
Many thanks!
Use Rx.Observable.fromPromise(promise)
fromPromise:
Converts a Promises/A+ spec compliant Promise and/or ES2015 compliant
Promise or a factory function which returns said Promise to an
Observable sequence.
example:
var source = Rx.Observable.fromPromise(promise);
var subscription = source.subscribe(
function (x) {
console.log('Next: %s', x);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
update
rxjs6 method is from
update
As of rxjs6 you can use from()
Did you tried to use the fromPromise() API of rxjs5 ?
Check it's documentation here !
I found the answer here (Just slightly differently named)
rxjs using promise only once on subscribe
So for my example the answer is as simple as:
var loadCountries = function () { return $http.get('/countries'); };
var observable = Rx.Observable.defer(loadCountries).shareReplay();
This is how you can use Observables
Lets say you have a method called getuser(username).
//Returns an observable
getUser(username){
return $http.get(url)
.map(res => res.json());
}
And you can use it as below
getUser.subscribe(res => console.log(response));
BUT if you want to use promises
//Returns an Promise
//Donot forget to import toPromise operator
getUser(username){
return $http.get(url)
.map(res => res.json())
.toPromise();
}
And you can use it as below
getUser.then(res => console.log(response));
I have a file where I'm writing things:
var stream = fs.createWriteStream("my_file.txt");
stream.once('open', function(fd) {
names.forEach(function(name){
doSomething(name);
});
stream.end();
});
This is working ok and I'm able to write to the file.
The problem is that the doSomething() function has some parts that are asynchronous. An example can be given with the dnsLookup function. Somewhere in my doSomething() I have:
dns.lookup(domain, (err, addresses, family) => {
if(err){
stream.write("Error:", err);
}else{
stream.write(addresses);
}
});
Now, my problem is, since the DNS check is asynchronous, the code keeps executing closing the stream. When the DNS response finally comes it cannot write to anywhere.
I already tried to use the async module but it didn't work. Probably I did something wrong.
Any idea?
Now that NodeJS is mostly up to speed with ES2015 features (and I notice you're using at least one arrow function), you can use the native promises in JavaScript (previously you could use a library):
var stream = fs.createWriteStream("my_file.txt");
stream.once('open', function(fd) {
Promise.all(names.map(name => doSomething(name)))
.then(() => {
// success handling
stream.end();
})
.catch(() => {
// error handling
stream.end();
});
});
(The line Promise.all(names.map(name => doSomething(name))) can be simply Promise.all(names.map(doSomething)) if you know doSomething ignores extra arguments and only uses the first.)
Promise.all (spec | MDN) accepts an iterable and returns a promise that is settled when all of the promises in the iterable are settled (non-promise values are treated as resolved promises using the value as the resolution).
Where doSomething becomes:
function doSomething(name) {
return new Promise((resolve, reject) => {
dns.lookup(domain, (err, addresses, family) => {
if(!err){ // <== You meant `if (err)` here, right?
stream.write("Error:", err);
reject(/*...reason...*/);
}else{
stream.write(addresses);
resolve(/*...possibly include addresses*/);
});
});
});
There are various libs that will "promise-ify" Node-style callbacks for you so using promises is less clunky than the mix above; in that case, you could use the promise from a promise-ified dns.lookup directly rather than creating your own extra one.