I am overriding a javascript function like this :
(function() {
origFunc = aFunction;
aFunction = function() {
doRequest();
//return origFunc.apply(this);
};
})();
I know that I need to end the function with "return origFunc.apply(this)" in order to execute the original function. However, as I'm executing a request, I have to wait until the request is done. That's why I wrote this function :
doRequest: function()
{
try
{
if(window.XMLHttpRequest)
httpRequest = new XMLHttpRequest();
else if(window.ActiveXObject)
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
var url = anUrl, self = this;
httpRequest.onreadystatechange = function(data)
{
try
{
if(httpRequest.readyState == 4)
{
if(httpRequest.status == 200)
return origFunc.apply(self);
else if(httpRequest.status != 0 )
alert("Error while executing the request : "+httpRequest.status+"\r\nUrl : "+url);
}
}
catch(e)
{
}
};
httpRequest.open("GET", url);
httpRequest.send();
}
catch(err)
{
alert("Error : "+err);
}
}
As you can guess, the problem is that I can't do the things like that.
Do you know how I could do ?
Here is an example for how to deal with wrapping async functions
// This simply calls the callback with some data after a second
// Could be an AJAX call for example
var doSomethingAsync = function (callback) {
setTimeout(function () {
callback({ some: 'data' });
}, 1000);
};
var fnThatMakesAsyncCall = function () {
// From the outside there is no way to change this callback
// But what if we need to intercept the async function to change the data given to it, or monitor it?
// Then we'd have to wrap the async function to wrap the callback.
var callback = function (data) {
console.log('Original', data);
};
doSomethingAsync(callback);
};
// Function to wrap another function and return the wrapper
var wrapFn = function (fn) {
// Create the wrapped function.
// Notice how it has the same signature with `callback` as the first argument
var wrapped = function (callback) {
// Here we get the original callback passed in
// We will instead wrap that too and call the original function with our new callback
var newCb = function (data) {
// This will run once the async call is complete
// We will as an example mutate the data in the return data of the callback
data.some = 'Wrapped it';
// Call the original callback with the changed data
callback.call(this, data);
};
// Run the function we wrap with the new callback we supply
fn.call(this, newCb);
};
// Return wrapped function
return wrapped;
};
// Will log Original {some: "data"}
fnThatMakesAsyncCall();
doSomethingAsync = wrapFn(doSomethingAsync);
// Will log Original {some: "Wrapped it"}
fnThatMakesAsyncCall();
Related
I'm looping around a JS function after an AJAX call for XML. When I use return it is undefined, even if I do if (i==x.length) {return}.
I would like the getInfo function to return the node values array. Which should be fairly simple, all of the code works apart from the return part.
var myFunction = {
sendAjax: function (url, success) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('POST', url);
xhr.onload = function () {
if (xhr.readyState > 3 && xhr.status == 200) success(xhr.responseXML);
};
xhr.send();
return xhr;
},
getInfo: function () {
myFunction.sendAjax('XXXXXXXXX', function (data) {
var i;
var xmlDoc = data
var x = xmlDoc.getElementsByTagName("Session");
var sessions = [];
for (i = 0; i < x.length; i++) {
sessions[i] += xmlDoc.getElementsByTagName("XXXX")[i].childNodes[0].nodeValue + ","
console.log(sessions[i]);
}
return sessions;
});
}
}
myFunction.getInfo(function(value){
console.log('mylog=' + value);
alert(value);
});
Result comes back as undefined, it IS looping around and returning the values fine, but the return is returning before the loop is finished. I have tried doing an if statement i.e. if (i==x.length) then return ... but that does not work.
You're misunderstanding how asynchronous functions and returns interact. Execution will continue as soon as all code in the control flow has been carried out, without waiting for async callbacks to complete. Take a look at this stripped down example:
function foo(){
setTimeout(function(){
return 5;
}, 500);
}
//calling foo
alert(foo());
Note how it alerts undefined and not 5. This is because the calling code continues executing as soon as foo() is finished running, and doesn't wait for the timeout to execute. Therefore, foo() returns nothing, and alert() alerts undefined.
The correct, callback way to write the above would be:
function foo(callbackFn){
setTimeout(function(){
callbackFn(5);
}, 500);
}
foo(function(value){
alert(value);
});
I want to create a listener function to listen changes of global variable. The use case is, when I made a ajax call, i flag isAjaxDone variable to false, once its done then flag it to true. So the listener will process something once detected the isAjaxDone is true.
i tried asyc ... await & Promise but i still can't achieve what i want. The entire method still run asynchronously outside, except the method inside asyc ... await & Promise.
Here is what i have tried:
var isAjaxDone = null
var timeout = 0
function listener(){
let waiter = function(){
return new Promise(resolve=>{
setTimeout(() => {
timeout += 1
listener()
}, 100);
})
}
if(isAjaxDone) return true
if(isAjaxDone === null) return false
if(isAjaxDone === false){
if(timeout < 300){
return waiter()
}
else{
return "timeout"
}
}
}
Implementation:
function checker(){
var ajaxStatus = listner()
if(ajaxStatus){
//...
}
}
When i call isAjaxDone, it will return me a Promise function instead of boolean.
I prefer not to use Promise...then because the function i wrote is consider as library, I don't want the user wrap a bunch of code inside the then because it will caused some problem to user code structure. Same goes to the Callback.
I would like to let it wait until either return timeout or boolean only, please advise.
You could do something like:
var xhr = new XMLHttpRequest;
xhr.open('POST', yourURLHere);
var promise = new Promise(function(resolve, reject){
xhr.onload = function(){
var o = JSON.parse(this.responseText); // should be `json_encode(['testProperty' => true])`ed response
if(o.testProperty === true){
resolve(true);
}
else{
reject(false);
}
}
xhr.send(formData); // you should get used to FormData
});
promise.then(function(resolveResult){
yourGlobalVar = resolveResult;
});
Of course, I would just make a post function and execute a function when all is complete, like:
function post(url, formData, success, successContext){
var xhr = new XMLHttpRequest;
var c = successContext || this;
xhr.open('POST', url);
xhr.onload = function(){
success.call(c, JSON.parse(xhr.responseText));
}
xhr.send(formData);
return xhr;
}
Now you can reuse:
var fd = new FormData;
fd.append('output', true);
// PHP could look like
/* if(isset($_POST['output']) && $_POST['output'] === true){
echo json_encode(['result' => true]);
}
*/
post('someURL.php', fd, function(resultObj){
globalVar = resultObj.result; // should be true since we sent that
});
Why not use an AJAX API that is already awaitable like fetch? It is polyfillable.
const request = new Request('https://example.com', {method: 'POST', body: '{"foo": "bar"}'});
(async() => {
const response = await fetch(request);
return await response.json();
})()
Hello there code wizards,
I am trying to get json data from the specified url down below and use it in a React component outside of the getWeather() function. What are the efficient ways to pass along an object from the innermost to outside? my console reads undefined. I believe there is an issue with variable scoping... Thanks for an idea to solve it.
Below is the code
function getWeather() {
var url = 'http://api.openweathermap.org/data/2.5/weather?zip=3000,au';
var apiKey= "005fa98ae858a29acf836ecdefac0411";
var httpRequest;
makeRequest();
var response;
function makeRequest() {
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = responseMethod;
httpRequest.open('GET', url + '&appid=' + apiKey);
httpRequest.send();
}
function responseMethod() {
if(httpRequest.readyState === 4) {
if(httpRequest.status === 200) {
updateUISucess(httpRequest.responseText);
} else {
}
}
}
function updateUISucess(responseText) {
return response = JSON.parse(responseText);
// I would like to get this JSON object out so that it logs on the console.
}
return response;
};
console.log(getWeather());
Chrome, now allow return on you function, u need synchronous request. try node webkit for do you request.
You can use the callback method pattern to get the data and use it outside
//Get weather function which accepts a callback function as a parameter
function getWeather(callback) {
var url = 'http://api.openweathermap.org/data/2.5/weather?zip=3000,au';
var apiKey = "005fa98ae858a29acf836ecdefac0411";
var httpRequest;
makeRequest();
function makeRequest() {
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = responseMethod;
httpRequest.open('GET', url + '&appid=' + apiKey);
httpRequest.send();
}
function responseMethod() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
try {
//Parse response
var data = JSON.parse(httpRequest.responseText);
//Invoke callback function with first arg null and second with result
callback(null, data);
} catch (e) {
//JSON parse failed
//Invoke callback with first arg as error object
callback(e)
}
} else {
//Invoke callback with first arg as error object
callback({
success: false,
status: httpRequest.status
});
}
}
}
};
function Weather(props) {
return <p>{JSON.stringify(props.result)}</p>;
}
//Callback which accepts err and result
function handleResult(err, result) {
if (err) {
//Check for errors and return early if needed
console.log("Error!", JSON.stringify(err));
return;
}
//Assign to react state here
console.log(result);
const element = <Weather result ={result}/ > ;
ReactDOM.render(
element
);
}
//Invoke getWeather with callback function as parameter
getWeather(handleResult);
Because of ajax (asynchronous) process js run continuously by line.
just make a callback function and pass it to calling function.
function getWeather(cb) {
var url = 'http://api.openweathermap.org/data/2.5/weather?zip=3000,au';
var apiKey= "005fa98ae858a29acf836ecdefac0411";
var httpRequest;
makeRequest();
var response;
function makeRequest() {
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = responseMethod;
httpRequest.open('GET', url + '&appid=' + apiKey);
httpRequest.send();
}
function responseMethod() {
if(httpRequest.readyState === 4) {
if(httpRequest.status === 200) {
updateUISucess(httpRequest.responseText);
} else {
}
}
}
function updateUISucess(responseText) {
// return
response = JSON.parse(responseText);
// I would like to get this JSON object out so that it logs on the console.
cb(response);
}
return response;
};
getWeather(cb);
function cb(res){
alert(res);
console.log(res);
}
I'm trying to write a small XHR abstraction as well as learn how to create chainable methods, I am nearly there (I think), but am at a loss as to what to do next, I think my setup is wrong.
What I want to do:
$http.get('file.txt')
.success(function () {
console.log('Success');
})
.error(function () {
console.log('Error');
});
What I've got:
window.$http = {};
$http.get = function (url, cb, data) {
var xhr = {
success: function (callback) {
callback();
return this;
},
error: function (callback) {
callback();
return this;
}
};
// just a test to call the success message
if (window) {
xhr.success.call(xhr);
}
return xhr;
};
I'm having trouble 'wiring' up the success/error messages, can anybody help point me in the right direction? Thanks in advance.
jsFiddle
Your chaining is OK, but you have a error at this line:
if (window) {
xhr.success.call(xhr); // Uncaught TypeError: undefined is not a function
}
So JavaScript breaks and doesn't return xhr. Delete thoses lines and it will work.
success and error are simply functions that store the passed functions into an internal storage. Once the XHR responds, your code should execute all callbacks accordingly, depending on the response status.
Now what you need is an object instance per request that stores its own set of success and error callbacks. Also, success and error methods should return the same instance to allow chaining.
This should set you to the right track:
(function (window) {
window.$http = {};
// An object constructor for your XHR object
function XHRObject(url,data){
// store the request data
this.url = url;
this.data = data;
// The callback storage
this.callbacks = {};
this.init();
}
// Methods
XHRObject.prototype = {
init : function(){
// Actual call here
// Depending on result, execute callbacks
var callbacksToExecute;
if(readyState === 4 && response.status === 200){
callbacksToExecute = this.callbacks.success;
} else {
callbacksToExecute = this.callbacks.error;
}
callbacksToExecute.forEach(function(callback){
callback.call(null);
});
},
success : function(cb){
// Create a success callback array and store the callback
if(this.callbacks.hasOwnProperty('success') this.callbacks.success = [];
this.callbacks.success.push(cb);
// You also need a flag to tell future callbacks to execute immediately
// if the current object has already responded
return this;
},
...
}
// A call to get basically returns an object
$http.get = function (url, data) {
return new XHRObject(url,data);
};
})(this);
I hope you can make something out of this:
window.$http = {};
$http.get = function (url, cb, data) {
var xhr = function(){
return {
success: function (callback) {
callback();
return this;
},
error: function (callback) {
callback();
return this;
}
};
};
return new xhr();
}
$http.get('url','cb','data')
.success(function () {
console.log('Success');
})
.error(function () {
console.log('Error');
});
Edit: I just realized this is basically the same code you wrote, except I'm missing the if(). It seems that test was causing the code to break.
<script type="text/javascript">
var geo = new GClientGeocoder();
function showAddress() {
var search = document.getElementById("search").value;
// getLocations has not ret, so wtf!
geo.getLocations(search, function (result) { (result.Status.code == 200) ? alert(result.Placemark[0].Point.coordinates) : alert(result.Status.code); });
}</script>
I need the ret value of the callback as getLocations() returns no values. How can I do this?
You can't. You have to write your code in such a way that the code that needs the result value is executed in the callback.
Example (I just named the function in a way which seems logical to me):
function drawPlacemarks(marks) {
// do fancy stuff with the results
alert(marks[0].Point.coordinates);
}
function getAddress(callback) {
var search = document.getElementById("search").value;
geo.getLocations(search, function (result) {
if(result.Status.code == 200) {
// pass the result to the callback
callback(result.Placemark);
}
});
}
getAddress(drawPlacemarks);