I'm facing an issue with promises..and was banging my head around from almost an hour now...
this.getDocument(documentId)
.then(function (response) {
console.log('in first then')
return 'from first then';
}).then(function (response) {
console.log(response)
});
Ideally the above code should give following output
in first then
from first then
But the actual output is as follows
in first then
undefined
Now the problem here is why the second then is getting response as undefined when I'm returning something from the first then.
[EDIT 1] Adding getDoument code
function getDocument(documentID) {
var config = {
url: '<URL>' + documentID,
headers: {enter code here
'Content-Type': 'application/json'
}
};
return HttpRequest.get(config);
}
var HttpRequest = (function () {
function HttpRequest() {
}
HttpRequest.get = function (config) {
var deferred = Q.defer();
var http = new XMLHttpRequest();
var url = config.url;
var authToken = window.localStorage.getItem('token');
http.open("GET", url, true);
Object.keys(config.headers).map(function (k) {
http.setRequestHeader(k, config.headers[k]);
});
http.setRequestHeader("Authorization", 'Bearer ' + authToken);
http.onreadystatechange = function () {
if (http.readyState !== 4)
return;
var response = http.responseText;
if (http.status != 200)
return deferred.reject(response);
deferred.resolve(response);
// if (/^[^2]\d\d$/.exec(http.status)) return deferred.reject(http.status);
};
http.send();
return deferred.promise;
};
HttpRequest.post = function (config) {
};
return HttpRequest;
}());
Related
I can be considered new to Node.JS so apologies, in here I am trying to make a function that yields code execution until the code finished making a HTTP request (using the "request" npm module) which then will be returned, the issue is that the library does not yield the code execution, I have tried using promise but it still won't yield code execution.
Original code:
const request = require("request")
// CONFIG
const ROBLOSECURITY = ""
var http_header = {
"Cookie": ".ROBLOSECURITY="+ROBLOSECURITY
}
function MakeRbxReq(http_method, url, payload) {
var jsonbody
var retfunc = {}
try {
jsonbody = JSON.stringify(payload)
} finally {}
var options = {
uri: "http://" + url,
body: jsonbody || "",
methpd: http_method,
headers: http_header
}
request(options, function(_, res) {
if (http_method.toUpperCase() == "POST" || http_method.toUpperCase() == "PUT" || http_method.toUpperCase() == "PATCH" || http_method.toUpperCase() == "DELETE") {
if (res.headers["X-CSRF-TOKEN"]) {
http_header["X-CSRF-TOKEN"] = res.headers["X-CSRF-TOKEN"]
options["headers"] = http_header
if (res.statusCode == 403) {
request(options, function(_, res) {
retfunc = {statusCode: res.statusCode, body: res.body}
})
} else {
retfunc = {statusCode: res.statusCode, body: res.body}
}
}
}
retfunc = {
statusCode: res.statusCode,
body: res.body
}
return
})
return retfunc
}
console.log(MakeRbxReq("GET", "search.roblox.com/catalog/json?CatalogContext=2&Subcategory=6&SortType=3&SortAggregation=5&Category=6"))
Promise attempt:
const request = require("request")
// CONFIG
const ROBLOSECURITY = ""
var http_header = {
"Cookie": ".ROBLOSECURITY="+ROBLOSECURITY
}
function MakeRbxReq(http_method, url, payload) {
var jsonbody
var retfunc = {}
try {
jsonbody = JSON.stringify(payload)
} finally {}
var options = {
uri: "http://" + url,
body: jsonbody || "",
methpd: http_method,
headers: http_header
}
async function req() {
let reqPromise = new Promise(function(resolve, reject) {
request(options, function(err, res) {
console.log("resolving")
resolve({statusCode: res.statusCode, body: res.body})
})
})
}
req()
return retfunc
}
console.log(MakeRbxReq("GET", "search.roblox.com/catalog/json?CatalogContext=2&Subcategory=6&SortType=3&SortAggregation=5&Category=6"))
Output from using promise:
C:\Program Files\nodejs\node.exe .\index.js
{}
resolving
request (promise) is asynchronous.
You should work with await or then
Here are some examples
I have this script that I use to import some data from an API, and into my database. Since this process is very time consuming, it often times out because on some of the items processed there is a lot of data to process..
I came with this solution a while ago, using promises, to first do the request to the API, then after it finishes I would prepare the data and put it into a temporary csv file, then I would fire another request to split that file into multiple smaller files, then... you get the idea... it was working, but I need to add to it some extra requests, I just can't make it work... I probably just need to simplify my logic.
Anyone can help me improve this code to make it easier to add those extra requests and keep it sending one request after the other?
This is the (over simplified) script in question:
window.importTrialsScripts = {};
window.addEventListener('DOMContentLoaded', function() {
importTrialsScripts.app.initialize();
});
(function(importTrialsScripts, document, $) {
importTrialsScripts = importTrialsScripts || {};
const app = {
ajaxurl: 'myajaxurl',
initialize: function() {
this.submitHandler();
},
submitHandler: function() {
const self = this;
document.querySelector('#start-import').addEventListener('click', function() {
self.pullTrialsFromApi();
});
},
pullTrialsFromApi: function() {
let data = new FormData();
data.append('action', 'pull_trials_from_api');
[123, 456, 789].forEach(function(str) {
data.append('ids[]', str);
});
this.startPullingTrials(data);
},
startPullingTrials: function(data) {
const self = this;
let promise = new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if (! response.success) {
alert('The API could not be reached. Please try again.');
console.error('Error!!', response);
return;
}
resolve(response.data);
}
else {
console.error('there was an error in the request', this);
reject(this);
}
});
});
promise.then(function(chunks) {
const processingChunks = Object.values(chunks).map(function(chunk) {
return self.processChunk(chunk);
});
Promise.all(processingChunks).then(function (processedTrials) {
console.log('finished', processedTrials);
});
}, function(err) {
console.error('promise rejected', err);
});
},
processChunk: function(chunkTrials) {
const self = this;
let data = new FormData();
data.append('action', 'process_trials_chunk');
Object.values(chunkTrials).forEach(function(chunk) {
data.append('chunk[]', JSON.stringify(chunk));
});
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if (! response.success) {
console.error('Error!!', response.data);
return;
}
resolve(response.data);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
splitToMultipleFiles: function() {
const self = this;
const data = new FormData();
data.append('action', 'split_location_files');
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if (this.status === 200) {
const response = JSON.parse(this.response);
if ( ! response.success ) {
console.error('Error!!', response.data);
return;
}
resolve(response.data.files);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
processLocation: function(file) {
const self = this;
let data = new FormData();
data.append('action', 'process_location_data');
data.append('file', file);
return new Promise(function(resolve, reject) {
self.sendAjaxRequest(data, function() {
if ( this.status === 200 ) {
const response = JSON.parse(this.response);
if (! response.success) {
console.error('Error!!', response.data);
return;
}
resolve(response.data);
}
else {
console.log('there was an error in the request', this);
reject(this);
}
});
});
},
sendAjaxRequest: function(data, callback) {
const self = this;
let xhr = new XMLHttpRequest();
xhr.open('POST', ajaxurl);
xhr.onload = callback;
xhr.addEventListener('timeout', function(e) {
console.error('the request has timed out', e);
});
xhr.addEventListener('error', function(e) {
console.error('the request returned an error', e);
});
xhr.addEventListener('abort', function(e) {
console.error('the request was aborted', e);
});
xhr.send(data);
},
};
$.extend(importTrialsScripts, {
app: app
});
}).apply(this, [window.importTrialsScripts, document, jQuery]);
I want to convert a jquery function into a javascript function:
window.parent.$.ajax({
type: 'GET',
url: "http://localhost:3063/corsService/GetCultureInformation",
contentType: "application/json",
dataType: "json",
success: function (data) {
numberDecimalDigit = data.NumberDecimalDigits;
},
async: false
});
I converted it to:
var request = new XMLHttpRequest();
request.open('GET', 'http://localhost:3063/corsService/GetCultureInformation', false);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// Success!
numberDecimalDigit = data.NumberDecimalDigits;
var resp = this.response;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
but I have errors:
1: XMLHttpRequest: Network Error 0x2efd, Could not complete the operation due to error 00002efd.
2: NetworkError
//Better use promises, as it reduces biolerplate heavy code of XMLhttp request provides.
function loadjson(file) {
return new Promise((resolve, reject) => {
return fetch(file).then((response) => {
if (response.ok) {
resolve(response.json());
} else {
reject(new Error("error"));
}
});
});
}
var newFile=loadjson("https://api.postalpincode.in/pincode/110001").then((data) => {
console.log(data);
});
I am new to Promise concepts and trying to wrap my head around but now I`` am confused here
const request = require("request");
const cheerio = require("cheerio");
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var url = require("url");
module.exports = {
resturant: resturant,
};
var resturanttables = [];
function resturant(url, day) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, html) {
if (error) {
return reject(error);
} else if (response.statusCode !== 200) {
return reject("Something is wrong! CINEMA")
}
httplogin("zeke", "coys", url, day);
console.log(resturanttables, "i am here");
resolve(resturanttables);
});
});
}
function httpafterlogin(url, cookie, day) {
request.get({
headers: {
'content-type': 'text/html',
'Cookie': cookie
},
url: url,
},
function(error, response, body) {
console.log(day)
var $ = cheerio.load(body);
if (day === "Friday") {
$(".WordSection2 p span ").each(function(li) {
// console.log(day, $(this).text())
resturanttables.push($(this).text());
console.log(resturanttables, "nside");
});
} else if (day === "Saturday") {
$(".WordSection4 p span").each(function(li) {
resturanttables.push($(this).text())
});
} else {
$(".WordSection6 p span").each(function(li) {
resturanttables.push($(this).text())
});
}
});
}
function httplogin(username, password, urls, day) {
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: urls,
form: {
"username": username,
"password": password
}
}, function(error, response, body) {
var cookie = response.caseless.dict['set-cookie'][0];
var location = response;
console.log(response.statusCode);
cookie = cookie.substring(0, cookie.indexOf(';'));
// httpafterlogin('http://vhost3.lnu.se:20080/dinner/'+response.headers.location, cookie);
var newurls = url.resolve(urls, response.headers.location)
httpafterlogin(newurls, cookie, day);
// console.log(response.headers, "jdjdjjdjdjjdjdjdjjdjjdjdj")
});
}
and then I call the function
loadPage.resturant("http://vhost3.lnu.se:20080/dinner/login", "Friday").then(function(data) {
console.log(data, "did it work now ")
})
the problem is that it returns the empty array. But when i tried to check and console.log in the afterlogin function and i could see that the array was actually filled, but that code runs after the promise has been resolved.
IN SHORT: how can I bound the resolve in restaurant promise not to send the data until the login function is completed?
in other words how can i get the filled array with information from afterlogin funtion?
rewrite httplogin and httpafterlogin to return promises:
function httpafterlogin (url, cookie, day) {
return new Promise(function (resolve, reject) {
request.get({
headers: {
'content-type': 'text/html',
'Cookie': cookie
},
url: url
}, function (error, response, body) {
if (error) {
reject(error);
} else {
resolve(body);
}
});
}).then(function (body) {
console.log(day);
var $ = cheerio.load(body);
if (day === "Friday") {
$(".WordSection2 p span").each(function (li) {
// console.log(day, $(this).text());
resturanttables.push($(this).text());
console.log(resturanttables, "nside");
});
} else if (day === "Saturday") {
$(".WordSection4 p span").each(function (li) {
resturanttables.push($(this).text());
});
} else {
$(".WordSection6 p span").each(function(li) {
resturanttables.push($(this).text());
});
}
});
}
function httplogin(username, password, urls, day) {
return new Promise(function (resolve, reject) {
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: urls,
form: {
"username": username,
"password": password
}
}, function(error, response, body) {
if (error) {
reject(error);
} else {
resolve(response);
}
});
}).then(function (response) {
var cookie = response.caseless.dict['set-cookie'][0];
var location = response;
console.log(response.statusCode);
cookie = cookie.substring(0, cookie.indexOf(';'));
var newurls = url.resolve(urls, response.headers.location)
return httpafterlogin(newurls, cookie, day);
});
}
then use .then like rsp suggested:
function resturant(url, day) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, html) {
if (error) {
return reject(error);
} else {
resolve(response);
}
})
}).then(function (response) {
if (response.statusCode !== 200) {
throw new Error("Something is wrong! CINEMA");
}
return httplogin("zeke", "coys", url, day)
}).then(function () {
console.log(resturanttables, "i am here");
return resturanttables;
});
}
this way, the block containing resolve(restautanttables) will not get called until httplogin completes
Use promises throughout your code - you can simplify your code using the request-promise package in place of the request package. All requests become promises and the code is easier to read and maintain.
const rp = require("request-promise");
const cheerio = require("cheerio");
const url = require("url");
function resturant(url, day) {
rp(url)
.then(function(){
// URL returned a 200 response
// so attempt to perform login
httplogin("zeke", "coys", url, day)
.then(function (data) {
// Promise is resolved here
return data;
});
})
.catch(function(error){
// just throwing the error
throw error;
});
}
function httplogin(username, password, urls, day) {
var options = {
headers: {
"content-type": "application/x-www-form-urlencoded"
},
uri: urls,
form: {
username: username,
password: password
},
method: "POST",
resolveWithFullResponse: true
};
rp(options)
.then(function (response) {
// POST succeeded
// grab the cookie
var cookie = response.caseless.dict['set-cookie'][0]
.substring(0, cookie.indexOf(';'));
// get new url string
var newurls = url.resolve(urls, response.headers.location);
httpafterlogin(newurls, cookie, day)
.then(function (tables) {
return tables;
})
.catch(function (error) {
// just throwing the error
throw error;
});
})
.catch(function (error) {
// Login failure
// just throwing the error
throw error;
});
}
function httpafterlogin(url, cookie, day) {
var options = {
headers: {
"content-type": "text/html",
"Cookie": cookie
},
uri: url,
transform: function (body) {
return cheerio.load(body);
}
};
rp(options)
.then(function ($) {
// body has been transformed and
// can now be processed with jQuery
// initialise the tables array
var tables = [];
// DRY code
// set default selector
var selector = ".WordSection6 p span";
// change the selector for Friday/Saturday
if (day === "Friday") {
selector = ".WordSection2 p span ";
} else if (day === "Saturday") {
selector = ".WordSection4 p span";
}
// process the selected section
$( selector ).each(function(li) {
tables.push($(this).text())
});
// crawling complete
return tables;
})
.catch(function (error) {
// Crawling failure
// just throwing the error
throw error;
});
}
If you don't want the promise to get resolved before the login is completed then you will either have to make your httplogin function take a callback and run it like this:
httplogin("zeke", "coys", url, day, function (err) {
if (err) {
reject(err);
} else {
resolve(resturanttables);
}
});
or make it return a promise and run it for example like this:
httplogin("zeke", "coys", url, day).then(function () {
resolve(resturanttables);
}).catch(function (err) {
reject(err);
});
There are more ways to do it with promises but this is the simplest way.
Either way you have to make your httplogin function signal its completion by either calling the callback that it takes as an argument or resolving the promise that it returns.
I have a modified code in react-native for fetching data with server, that works fine. I want to add NetInfo to always check before fetching if telephone has connection to internet. Is it posible inside promise? How to connect this async function to my code?
'use strict';
var MAX_WAITING_TIME = 30000
var processStatus = function (response) {
// status "0" to handle local files fetching (e.g. Cordova/Phonegap etc.)
if (response.status === 200 || response.status === 0 || response.status === 201 || response.status === 422 || response.status === 302 ) {
return Promise.resolve(response)
} else if(response.status === 413) {
return Promise.reject(alert(____mobile.connection_error.large_file))
} else {
//return Promise.reject(alert("Process status: "+JSON.stringify(response )))
return Promise.reject(alert(____mobile.connection_error.top));
console.log("Process status: "+JSON.stringify(response ));
}
};
var parseJson = function (response) {
return response.json();
};
var getWrappedPromise = function () {
var wrappedPromise = {},
promise = new Promise(function (resolve, reject) {
wrappedPromise.resolve = resolve;
wrappedPromise.reject = reject;
});
wrappedPromise.then = promise.then.bind(promise);
wrappedPromise.catch = promise.catch.bind(promise);
wrappedPromise.promise = promise;// e.g. if you want to provide somewhere only promise, without .resolve/.reject/.catch methods
return wrappedPromise;
};
/* #returns {wrapped Promise} with .resolve/.reject/.catch methods */
var getWrappedFetch = function () {
var wrappedPromise = getWrappedPromise();
var args = Array.prototype.slice.call(arguments);// arguments to Array
fetch.apply(null, args)// calling original fetch() method
.then(function (response) {
wrappedPromise.resolve(response);
}, function (error) {
// wrappedPromise.reject(alert("Fetch status: " + error));
wrappedPromise.reject(____mobile.connection_error.top);
console.log("Fetch status: " + error);
})
.catch(function (error) {
wrappedPromise.catch(error);
});
return wrappedPromise;
};
/**
* Fetch JSON by url
* #param { {
* url: {String},
* [cacheBusting]: {Boolean}
* } } params
* #returns {Promise}
*/
var postJSON = function (params) {
var headers1 = {}
if (params.json){
headers1 = {
'Accept': 'application/json',
'Content-Type': 'application/json'}
}
if (params.headersIn){
headers1 = params.headersIn
}
var methodTmp = 'POST'
if (params.methodIn) {
methodTmp = params.methodIn
}
console.log(methodTmp)
var wrappedFetch = getWrappedFetch(
params.cacheBusting ? params.url + '?' + new Date().getTime() : params.url,
{
method: methodTmp,//'POST',// optional, "GET" is default value
headers: headers1,
body: params.send_data
});
var timeoutId = setTimeout(function () {
wrappedFetch.reject(alert(____mobile.connection_error.timeout, ____mobile.connection_error.check_connection));// reject on timeout
}, MAX_WAITING_TIME);
return wrappedFetch.promise// getting clear promise from wrapped
.then(function (response) {
clearTimeout(timeoutId);
return response;
})
.then(processStatus)
.then(parseJson);
};
module.exports = postJSON;
What would be the bast way to implement: NetInfo.isConnected.fetch() so fetched would only worked when there is internet connection?
EDIT:
I want to use:
NetInfo.isConnected.fetch()
Yeah I have to rewrite this code, not to use getWrappedPromise and now I think is good time for it.
EDIT2: Ok I refactored this code fragment, hope its better. Any comments welcome. I tested and I'm not sure if I still need this NetInfo.isConnected.fetch(). Now there is no errors where there is no connection or am I missing something?
New code:
var processStatus = function (response) {
if (response == undefined) {
return null
}
// status "0" to handle local files fetching (e.g. Cordova/Phonegap etc.)
if (response.status === 200 || response.status === 0 || response.status === 201 || response.status === 422 || response.status === 302 ) {
return Promise.resolve(response)
} else if(response.status === 413) {
return Promise.reject(alert(____mobile.connection_error.large_file))
} else {
//return Promise.reject(alert("Process status: "+JSON.stringify(response )))
console.log("Process status: "+JSON.stringify(response ));
return Promise.reject(alert(____mobile.connection_error.top));
}
};
var parseJson = function (response) {
if (response == undefined) {
return null
}
return response.json();
};
var postJSON = function (params) {
var headers1 = {}
if (params.json){
headers1 = {
'Accept': 'application/json',
'Content-Type': 'application/json'}
}
if (params.headersIn){
headers1 = params.headersIn
}
var methodTmp = 'POST'
if (params.methodIn) {
methodTmp = params.methodIn
}
console.log(methodTmp)
var fetchPromise = fetch(params.cacheBusting ? params.url + '?' + new Date().getTime() : params.url,
{
method: methodTmp,//'POST',// optional, "GET" is default value
headers: headers1,
body: params.send_data
})// calling original fetch() method
.then(function (response) {
return response;
}, function (error) {
console.log("Fetch status: " + error);
return fetch
}).then(processStatus)
.then(parseJson);
// timeoutId = setTimeout(function () {
// wrappedFetch.reject(alert(____mobile.connection_error.timeout, ____mobile.connection_error.check_connection));// reject on timeout
// }, MAX_WAITING_TIME);
return fetchPromise
};