Promises then/catch - node.js

I have the following code:
return requestAsync({
method: 'GET',
url: 'https://' + servers[num - 1] + ':8033/version.txt'
}).then().catch()
I tried throwing an error in the then handler but that didn't work
If a condition is not met in the then handler, I want throw an error that the catch handler handles. How can I get that done?
Code:
var P = require('bluebird');
var defer = function () {
var resolve, reject;
var promise = new P(function () {
resolve = arguments[0];
reject = arguments[1];
});
return {
resolve: function () {
resolve.apply(null, arguments);
return promise;
},
reject: function () {
reject.apply(null, arguments);
return promise;
},
promise: promise
};
};
var pool = {maxSockets: Infinity};
var requestAsync = function (options) {
options.pool = pool;
options.timeout = 60000;
options.rejectUnauthorized = false;
options.strictSSL = false;
var deferred = defer();
var r = request(options, function (err, res, body) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(res, body);
});
deferred.promise.req = r;
return deferred.promise;
};
return requestAsync({
method: 'GET',
url: 'https://' + servers[num - 1] + ':8033/version.txt'
}).then(function (response) {
throw new Error('Server is not taken');
}).catch(function (err) { });

You can manually throw the error:
requestAsync({
method: 'GET',
url: 'https://' + servers[num - 1] + ':8033/version.txt'
})
.then(function () {
throw new Error("Catch me")
}))
.catch(function (error) {
console.error(error)
})
jsbin: https://jsbin.com/dewiqafaca/edit?html,js,console,output

Just use throw to generate a standard JavaScript exception in your then function and it should invoke the function in your catch block with whatever value you provide as the argument.

Related

Null in request [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
In that code, console.log(game) gives me an array, but return(game) gives me null.
I don't know, what should I do to gain that array
takeApi: async (root, args, { req }, info) =>{
let userNick='Izyi';
var request = require('request');
var JsonFind=require('json-find');
var url = 'https://someapi/'+userNick;
var game;
request.get({
url: url,
json: true,
headers: {'API-KEY': 'XXX'}
}, (err, res, data) => {
if (err) {
console.log('Error:', err);
} else if (res.statusCode !== 200) {
console.log('Status:', res.statusCode);
} else {
const doc= JsonFind(data.lifeTimeStats);
var matchesPlayed=(doc.checkKey('7').value);
var wins=(doc.checkKey('8').value);
var kills=(doc.checkKey('10').value);
game ={kills:kills,wins:wins,matchesPlayed:matchesPlayed}
console.log(game);
return(game);
}
})
return(game);
}
request.get works via a callback and is not directly compatible with async/await. That callback happens when the request is done or has errored out. The return(game); then happens before the request has completed.
You need to return a new Promise and then resovle or reject based on the results passed to the callback.
You can then await or .then takeApi and expect to have a value returned.
const takeApi = async(root, args, { req }, info) => {
let userNick = 'Izyi';
var request = require('request');
var JsonFind = require('json-find');
var url = 'https://someapi/' + userNick;
// return a Promise, which will work
// by the called using `await` or `.then`
return new Promise((resolve, reject) => {
request.get({
url: url,
json: true,
headers: {
'API-KEY': 'XXX'
}
}, (err, res, data) => {
if (err) {
console.log('Error:', err);
// error, reject
reject(err);
} else if (res.statusCode !== 200) {
console.log('Status:', res.statusCode);
// error, reject
reject(res.statusCode);
} else {
const doc = JsonFind(data.lifeTimeStats);
var matchesPlayed = (doc.checkKey('7').value);
var wins = (doc.checkKey('8').value);
var kills = (doc.checkKey('10').value);
const game = {
kills: kills,
wins: wins,
matchesPlayed: matchesPlayed
}
console.log(game);
// success, resolve
resolve(game);
}
})
});
}

var function calling for unknown reason

I have the code below, and it seems to call the var promiseFeedback is called and I don't know why... This means it is called even when an error occurs when I create document. Whereas is should only be called if there is no err in the createDocument.
Is anyone able to clear up why?
if (json) {
createDocument(documentUrl, context, json, function(res){
var promiseFeedback = callFB (context, res);
var collection = `mydb`
client.createDocument(collection, res, (err, result) => {
if(err) {
context.log(err);
return context.done();
} else {
Promise.all([promiseFeedback]).then(function(results){
context.log("promiseFeedback: " + results[0]);
context.done();
});
}
});
});
}
function callFB(context, res) {
return new Promise((resolve, reject) => {
var requestUrl = url.parse( URL );
var requestBody = {
"id": res.id
};
var body = JSON.stringify( requestBody );
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body),
}
};
var request = https.request(requestOptions, function(res) {
var data ="";
res.on('data', function (chunk) {
data += chunk
});
res.on('end', function () {
resolve(true);
})
}).on('error', function(error) {
context.log("request error:", error);
resolve(false);
});
request.write(body);
request.end();
});
}
var promiseFeedback = callFB (context, res);
This statement executes callFB immediately, not just assigns another name to the promise. This promise callFB is out of the callback(scope) of err and Promise.all([promiseFeedback]), it runs no matter what the result of client.createDocument is.
To fix this:
Remove var promiseFeedback = callFB (context, res); and change Promise.all([promiseFeedback]) to callFB(context, res). You don't need to use Promise.all as you only have one promise to resolve.
Or you can just move var promiseFeedback = callFB (context, res); into else segment.

Function enters then before request completed

My async function enters then before request is completed. Shouldn't Then part of the code executes only after the async function is completed? How to make the function call only when all the function has finished executing?
app.js
var request_test = require('./request_test');
baseUrl = "https://github.com";
promiseFunction().then((result)=>{
console.log("complete")
});
var promiseFunction = async function promiseFunction() {
request_test.request_test(baseUrl);
}
request_test.js
var request = require('request');
var cheerio = require('cheerio');
var request_test = function check(baseUrl) {
console.log("baseUrl:" + baseUrl)
var options = {
url: baseUrl
};
request(options, function (error, response, html) {
if (!error) {
console.log("no error");
}else{
console.log("else js");
console.log(error);
}
});
}
module.exports = {
request_test: request_test
};
In order to use then() you need to return a promise. So here is an example of the good old style promise chain, simply return promise from request_test and once you resolve or reject it, then() will be called:
promiseFunction().then((result) => {
console.log("complete");
});
function promiseFunction() {
return request_test();
}
function request_test() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("no error");
resolve();
}, 1000);
});
}
Or maybe use the modern approach - async method to await call function that returns promise.
promiseFunction();
async function promiseFunction() {
await request_test();
console.log('complete');
}
function request_test() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log("no error");
resolve();
}, 1000);
});
}
Your issue is coming from var request_test = function check(baseUrl) { ... inside this function you are not returning promise, you are even returning nothing :)
if you are using async I would go ahead and use the await/async syntax. Also the package request does not return a promise, you have an alternative with request-promise-native. The promise should be the return value of your helper function. It could look like this:
var request_test = require('./request_test');
var baseUrl = "https://github.com";
var promiseFunction = async function () {
var result = await request_test.request_test(baseUrl);
console.log("complete");
}
promiseFunction();
and the module:
var request = require('request-promise-native');
var cheerio = require('cheerio');
var request_test = function check(baseUrl) {
console.log("baseUrl:" + baseUrl)
var options = {
url: baseUrl
};
return request(options).then(function (error, response, html) {
if (!error) {
console.log("no error");
} else{
console.log("else js");
console.log(error);
}
});
}
module.exports = {
request_test: request_test
};

Regressive call in promise

Is there any easy way to do recursive call using promise. Here is my sample.
function getData() {
var result=[];
var deferred = Q.defer();
(function fetchData(pageno){
var options = {
method : 'GET',
url : 'example.com/test',
qs:{
pageNo: pageno
}
}
request(options, function (error, response, body) {
if (error)throw new Error(error);
if (body.hasMorePage == true) { //checking is there next page
result.push(body)
fetchData(++body.pageno); // getting next page data
} else {
deferred.resolve(result); // promise resolve when there is no more page
}
});
})(0);
return deferred.promise;
}
getData().then(function(data){
console.log(data)
});
Let's consider API is giving more data in consecutive calls. in order to collect all the data, I need to use some parameter (EX:hasMorePage) from previous call response. I need to go regressive call only for obtaining this scenario, but I would like to know a better(Promise) way.
Most welcome.
async function request(options, callback) {
// simulate server response of example.com/test with 1 second delay
const totalNumberOfPages = 3;
const pageNo = options.qs.pageNo;
await new Promise(resolve => setTimeout(resolve, 1000));
const hasMorePages = pageNo < totalNumberOfPages;
const body = { hasMorePages };
callback(void 0, { body }, body);
}
function getPage(pageNo) {
const options = {
method: 'GET',
url: 'example.com/test',
qs: { pageNo }
};
return new Promise(resolve => request(options, (error, response, body) => {
console.log('response received', response);
if(error) {
throw new Error(error);
}
resolve(body);
}));
}
async function getData() {
const result = [];
for(let i = 1, hasMorePages = true; hasMorePages; i++) {
const body = await getPage(i);
result.push(body);
hasMorePages = body.hasMorePages;
}
return result;
}
getData().then(data => console.log('RESULT', data));

how to get readStream with thunk in koa ?

I want to pipe a request in a koa controller, It's work:
var s = require('through2')();
var req = http.request(url, function(res) {
res.pipe(s);
})
req.end(null);
s.on('close', function() {
console.log('has close');
});
this.body = s;
But with thunk , it seems to be not work.
var s = stream();
yield thunk(url, s);
this.body = s;
Here is the thunk:
var thunk = function (url, s) {
return function(callback) {
var req = http.request(url, function(res) {
res.pipe(s);
});
s.on('close', function() {
callback(null, null);
console.log('req inner close');
});
req.end(null);
}
}
Use a promise for this (return a promise, not a thunk). Off the top of my head, so you may need to play around with it:
function run(url, s) {
return new Promise(function(resolve, reject) {
var req = http.request(url, function(res) {
res.pipe(s);
res.on('end', function() {
req.end();
});
});
req.on('error', function(err) {
return reject(err);
});
s.on('close', function() {
console.log('req inner close');
return resolve();
});
});
}
Then:
yield run(url, s);

Resources