Synchronous JSONP request - javascript

There are many questions out there about JSONP requests and the fact that they cannot be made synchronously. Most workarounds involve using the callbacks, or the success function in an ajax request to do what you want, but I don't think that's going to work for me.
Background: I'm working on a search application using Solr. I'm developing a javascript API for others to use to interact with Solr so they don't need to understand the ins and outs of a Solr search request.
In my api, I have a Request object, with a function called doRequest. The purpose of the function is to perform the call to the solr server (on another domain, thus the need for JSONP), and return a Response object.
Request.prototype.doRequest = function (){
var res = new Response();
$.ajax({
url: this.baseURL,
data: 'q=*:*&start=0&rows=10&indent=on&wt=json',
success: function(data){
res.response = data.response;
res.responseHeader = data.responseHeader;
/*
other...
stuff...
*/
},
dataType: 'jsonp',
jsonp: 'json.wrf'
});
res.request = this;
return res;
};
The "user" would use this function like so...
var req = new Request();
var res = req.doRequest();
and then do something or other with the results in res.
Given that I cannot do a synchronous JSONP request, and I cannot return from within the ajax function, I can't figure out anyway to make sure res is fully populated for the user before they start using it.
Thanks,

It looks like using callback functions is the way to do this. Here's how I ended up doing it in case you're interested.
Request.prototype.doRequest = function (callback){
var res = new Response();
$.ajax({
url: this.baseURL,
data: 'q=*:*&start=0&rows=10&indent=on&wt=json',
success: function(data){
res.response = data.response;
res.responseHeader = data.responseHeader;
res.request = this;
/*
other...
stuff...
*/
callback(res);
},
dataType: 'jsonp',
jsonp: 'json.wrf'
});
};
And now the user uses the function like so:
var req = new Request();
var res = req.doRequest(parseResults);
Where parseResults is the callback function defined by the user that takes the response object as a parameters.
function parseResults(res){
//Doing work
}

Whether or not the rest of your program is synchronous, there are times when you need to touch a REST interface synchronously. An example is where you have a request to get an array of assets (perhaps asset Ids) and then hydrate each of the Ids to get the full data/asset. If you've used the Ooyala API then you know what I mean.
I created what seems to be the first synchronous JSONP module to allow each next request to only run once its previous request has finished. It uses recursion instead of Promises, which means the next request will not be sent until the previous one is successful. The API lives here: https://github.com/cScarlson/jsonpsync
Hope this helps.

Related

call Nodejs function from url

I want to execute a function inside a remote URL. I know the page URL where the function is and I know the Function name too. The server-side application is built on NodeJs Express. And the function itself look like this
function executer(param1, parama2){
//logic
return true;
}
Is there any way to achieve this?
You can use for example an AJAX call to trigger an endpoint on server like this:
$.ajax({
url: "/remoteservice/executer/",
type: "get",
data: {"param1": "param1","param2":"param2"},
success: function(result){
alert("Job is done");
}
});
But you need to know the endpoint(url) and the method that it waits(get, post or whatever)
If it is some API. Then you can use any node module for request like request or node-fetch. First is for callback and second for promises based. Examples are listed in modules description.

MockJax is not sending response to my AJAX request in JavaScript application

I am using a jQuery library called MockAjax which allows you to mock/test real AJAX calls.
In my application I can use my live app version of an AJAX request and MockAjax will intercept the AJAX request and respond with a Mock response!
I am also using another library called M<ockJson which is similar but instead allows you to generate a Mock JSON response.
Using both libraries together, my Application makes an AJAX request. MockAjax catches the AJAX request and then MockJson generates and returns a random JSON response.
In my past projects this has worked great with no issues until today...
Now that my application is working pretty good, I decided it;s time to restructure the JavaScript into a more structured version. (putting DOM events, tasks, etc into sections of code).
This is where my problem began....
In my new code,
my App makes an AJAX request.
MockAjax catches the AJAX request.
MockJson is called to get the JSON response
ERRORS this is where it all goes wrong...
At this last step, it should pass the JSON response back to the original AJAX calls Success function. It simply does not!
I get no errors or anything in the console. I set up a simple alert() in my AJAX calls success() function and it does not make it that far to even trigger the alert!
I am not sure if there is some sort of scope issue or what the problem could be. When my app was flat, all variables and functions in the glbal root level with no structure to the app at all...it all worked. As soon as I moved everything into Objects, etc....it all works except this 1 issue of not returning the MockAjax response back to the Real Ajax response!
I removed 95% of the app code and re-built it with just the very minimal to run this example problem. The demo of the problem is here... http://jsbin.com/vugeki/1/edit?js
App flow:
projectTaskModal.init(); is ran on page load
This fires off projectTaskModal.mockAjax.init(); which sets up the MockAjax and MockJson code
Then projectTaskModal.task.openTaskModal(projectTaskModal.cache.taskId); is ran which executes the AJAX request
AJAX POST Request is sent to /gettaskevents
MockAjax catches the request sent to /gettaskevents
MockAjax then calls MockJson to generate the JSON response. projectTaskModal.mockAjax.generateTaskEventsJson(); calls that function and I have it printing the JSON respionse into the console so I can see that it is generating it!
In my MockAjax code, var taskevents holds the JSON response and then set it to this... this.responseText = taskevents; ``this.responseTextI believe is what is supposed to be returned to the Applications originalAJAX` call. It seems that this is where the problem might be! It does not seem to be returning the response back to the original AJAX code that requested it in the first place!
Could this be some sort of scope issue?
var projectTaskModal = {
cache: {
taskId: 1,
projectId: '12345',
},
init: function() {
projectTaskModal.mockAjax.init();
//console.log(projectTaskModal.mockAjax.init.generateTaskEventsJson());
projectTaskModal.task.openTaskModal(projectTaskModal.cache.taskId);
},
task: {
openTaskModal: function(taskId) {
// Load Task Events/Comments Panel from AJAX Request
projectTaskModal.task.loadTaskEventsPanel(taskId);
},
/**
* Load Task Events/Comments from backend Database JSON
* #param {string} jsonServerEndpoint URL for AJAX to Request
* #return {string} Generated HTML of all Task Events built from JSON
*/
loadTaskEventsPanel: function(taskId) {
// Request Task Events and Comments using AJAX Request to Server
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: '/gettaskevents',
data: {
action: 'load-task-events',
task_id: projectTaskModal.cache.taskId
},
success: function(data) {
alert('TESTING AJAX SUCCESS CALLBACK WAS CALLED!');
console.log('function loadTaskEventsPanel(taskId) DATA: ');
console.log(data);
// Parse JSON data
var taskEventsJson = data;
var task_events = taskEventsJson.task_events;
// Loop over each Task Event record returned
$.each(task_events, function(i, event) {
console.log('commentID: ' + event.commentId);
console.log('create_at DateTime: ' + event.created_at);
});
}
});
},
},
mockAjax: {
init: function(){
// Adding the #EVENT_TYPE keyword for MockJSON Template Usage
$.mockJSON.data.EVENT_TYPE = [
'Comment Created',
'Task Status Changed',
'Task Completed'
];
// Mock AJAX response for AJAX request to /gettaskevents
$.mockjax({
url: '/gettaskevents',
contentType: 'text/json',
responseTime: 2900, // Simulate a network latency of 750ms
response: function(settings) {
console.log('mockJax POST to /gettaskevents :');
//console.log(settings);
//DEBUG('Get Task Events JSON', settings.data);
if(settings.data.value == 'err') {
alert('MockAjax Error');
this.status = 500;
this.responseText = 'Validation error!';
} else {
alert('MockAjax Success');
//var taskevents = generateTaskEventsJson();
var taskevents = projectTaskModal.mockAjax.generateTaskEventsJson();
this.responseText = taskevents;
console.log(taskevents);
}
}
});
},
// Generate Mock JSON Response to load fake Task Evewnt/Comments JSON for Mock AJAX request
//var generateTaskEventsJson = function () {
generateTaskEventsJson: function() {
var mockTaskJson = $.mockJSON.generateFromTemplate({
"task_events|10-14" : [{
"commentId|+1" : 100000000,
"projectId|+1" : 100000000,
"taskId|+1" : 100000000,
"userId|+1" : 100000000,
"created_at" : "#DATE_YYYY-#DATE_MM-#DATE_DD",
"event_type" : "#EVENT_TYPE",
"userName" : "#MALE_FIRST_NAME #LAST_NAME",
"description" : "#LOREM_IPSUM #LOREM_IPSUM"
}]
});
//DEBUG('Generate Mock Task Events JSON', mockTaskJson.task_events);
//console.log(mockTaskJson.task_events);
//return mockTaskJson.task_events;
return mockTaskJson;
}
},
};
$(function() {
projectTaskModal.init();
});
Your JSBin example shows that you are using a very old version of Mockjax (1.5.0-pre). The latest is 1.6.2, released quite recently (I'm the core maintainer now). Below is a link to an updated JSBin where everything appears to be working just fine. The old version of Mockjax that you were running was created before jQuery 2.0 existed, and thus does not support it (1.6.2 does).
http://jsbin.com/qucudeleve/1/
So... update your Mockjax version to use Bower, npm, or just Rawgit (https://rawgit.com/jakerella/jquery-mockjax/master/jquery.mockjax.js) from the primary account (mine) versus your own fork which is extremely out of date!
Good luck.

Domain lookup using javascript

We have two domains(xyz.com and zxy.com). and using jquery ajax call to get the data from one domain.
If first one fails, how do i check and redirect to another domain using javascript.
Could you not just use window.location.host to find out which domain the user is currently on?
This way you can make the correct ajax call from the start. There is no reason to make a request to the wrong domain, wait for it to fail then make another request.
If you do however wish to actually make an AJAX request and wait for it to fail then make a different request it would be as follows (this answer is quite verbose on purpose):
var firstRequest = $.ajax({
url: 'http://xyz.com',
timeout: 5000
});
firstRequest.done(function (data) {
});
firstRequest.fail(function () {
var anotherRequest = $.ajax({
url: 'http://xzy.com',
timeout: 5000
});
anotherRequest.done(function (data) {
});
anotherRequest.fail(function () {
});
});

How can i stop ajax request (don't wait untill response come)?

If I use Ajax to send request and this request take long time ..... if I want to send anther request what should I do?
the current behaviour the second request (I did) waiting until the first request get with response.
NOTE :
i want to do this behaviour on whole application (any new request execute immediately not wait the old one to be finished firstly)
My application using (Ajax + PHP + jQuery + Symfony)
Assume that is the first request take long time:
$.ajax
({
type: "GET",
url: url1,
success: function (html)
{
// do some thing
}
});
In any time I want this request to execute and terminate the first one.
$.ajax
({
type: "POST",
url: url,
success: function (html)
{
// do some thing else
}
});
var xhrReq;
xhrReq = $.ajax(...);
// then if you want to stop the rqest and exit use :
xhrReq.abort();
It’s sort of a manual process, but you can add a global xhr object and test it on each request. If the readystate is "loading", abort it:
var xhr;
var loadUrl = function(url) {
if ( xhr && xhr.readyState > 0 && xhr.readyState < 4 ) {
// there is a request in the pipe, abort
xhr.abort();
}
xhr = $.get(url, function() {
console.log('success', this);
});
};
loadUrl('/ajax/');
The XMLHttpRequest object has an abort function. You can use setTimeout to abort a request that is taking too long.
EDIT: In the case you do not want to use a timer, and a new event occurs that should abort the prior request, then the event handler should do the following
if(!this.request) return; // request contains the XMLHttpRequest
this.request.onreadystatechange = function() {};
if(this.request.readyState != 4) {
this.request.abort();
}
Then after that you can create the new XMLHttpRequest object.
I have been working on this many ways and I feel I found a working solution. I had a caching process that was causing a page to hang until done (average 5 seconds). Yes this is better suited as a CRON job, but I needed to create caching process for the user without knowing the environment they are using for my CMS.
What I had done:
Create the call within a variable and then remove it by a hard delete. By deleting this it seems to be removing the wait. This "hack" seemed to pull the wait from 5 second average to a 325ms wait.
var ignore = $.ajax({
url:something/here.php,
type: "GET",
url: url1,
success: function(){}
});
delete ignore;
Defining the ajax request variable:
var xhr;
Making the ajax call:
xhr = $.ajax(...);
Aborting the ajax call:
xhr.abort();
Browser allows you to handle only limited amount of requests to same host at time (2 or 3 as I remember, depending on browser).
Workaround on requests count is to make fake domains - like img1.domain.com, img2.domain.com, etc. leading to the same host and randomly use them in requests. Then you can just make requests you need. Domains count should be chosen depending on requests quantity in order to keep in bounds - 2 requests per domain. Otherwise 3rd request will wait until one of active finishes.
It allows you to receive responses from all your requests.
For example, Google uses it to make images load faster.
EDIT:
Example: you have http://yourhost.com/ and alias http://alias.yourhost.com which points to the same place.
Then:
$.ajax
({
type: "GET",
url: 'http://yourhost.com/somescript.php',
success: function (html)
{
// do some thing
}
});
and then
$.ajax
({
type: "POST",
url: 'http://alias.yourhost.com/somescript2.php',
success: function (html)
{
// do some thing else
}
});

javascript: handling client side initiated objects that the server hasn't assigned an id to

I'm developing a javascript application and I'm trying to make server side syncing as automagic and unobtrusive as possible
The problem I'm facing is that when creating an object client side I can immediately send the create ajax request and while I'm waiting for it to return add the object to the ui where necessary
However since the object has no id until the server responds I can't perform any update or destroy actions on it until the server responds and updates its id
What is the best way of dealing with this problem?
Some code if it helps:
create_object = function() {
return {
save: function() {
if (this.isNew()) {
this.create();
} else {
this.update();
}
},
isNew: function() {
return (this.id === undefined || this.id === null);
},
update: function () {
$.ajax({
url: '/update_object/'+this.id+'.json',
type: 'post',
dataType: 'json',
data: this
});
},
create: function () {
var object = this;
$.ajax({
url: '/create_object',
type: 'post',
dataType: 'json',
data: this,
success: function(data) {
object.id = data.id;
}
});
},
destory: function () {
$.ajax({
url: '/destroy_object/'+this.id+'.json',
type: 'get',
dataType: 'json'
});
}
};
};
var object = create_object();
object.message = "Foo!";
object.save();
// this will create a new object until object.save has responded
object.message = "Bar!";
object.save();
// this wont work until object.save has responded
object.destroy();
This is not really a problem. AJAX is asynchronous by nature (Asynchronous Javascript and XML). You will have to wait until you get a response from the server to update your UI.
If you must update the UI immediately, you can create an element with a placeholder ID that you can then update with the actual ID once the server responds.
UPDATE
This is in response to your comment. Webapps are not purely client-side applications. They fit into the client-server paradigm. You can try using a synchronous post, but this has the side-effect of tying up the browser until the server responds (this is due to the fact that Javascript is single-threaded).
That being said, the response from the server should be pretty quick unless your network is slow or if whatever post your sending to the server results in some computationally-intensive operation.
Going by the placeholder route will (as you have realized) result in all sorts of new problems that you have to deal with. You have to ensure that they are unique. Now what if they perform some operation on the client-side element before the server responds with an id? The server won't know what the placeholder id means. There are ways around this (queuing requests is one way), but it will make your code a whole lot more complicated. I don't think the tradeoff is worth it just to make the UI update faster.
An option is to provide some visual feedback to the user that the app is "working" (i.e., while you are waiting for a response from the server). A spinner, for example.
As far as stacking the AJAX requests, that is one approach that you can take using the jQuery message-queuing plugin.

Categories

Resources