Skip to content
This repository has been archived by the owner on Jan 19, 2018. It is now read-only.

How to access previous Ajax response in a chain of ajax requests #8

Open
fbuchinger opened this issue Jan 10, 2011 · 3 comments
Open

Comments

@fbuchinger
Copy link

Hi,

I'm writing a javascript client for a webservice that requires a lot of inter-dependent requests (i.e. you need the parts of the response from request1 as GET parameters in request 2). To avoid the extensive use of nested callbacks, I like to develop the client using jquery/jsdeferred's next statement. To make my code even shorter, I like to register my custom request/response handler as Deferred shorthand function. Here is what I have so far:

Deferred.define();

function makeRequest (method, params){
    $.extend(params,{method: method, api_key: 123});
     var url = $.param('http://api.example.com', params);
    return next($.get(url))
}

Deferred.define(makeRequest, ["next","parallel"]);


makeRequest('getIdForUsername', {username:'dummy'}).
//user_id is from the response of 'getIfForUsername' request
makeRequest('getUserStatus', {user_id:user_id}).
next(function(userstatus){
    //generate HTML for user status
});

My questions:

  • how can I "pass on" the user_id obtained in the first request to parameters of the second request?
  • How can I differentiate between parallell and sequential execution of the makeRequest- function?
  • How can I implement error handling proberly? (e.g. request1 gives an error response --> chain should stop and user should be notified of bad response)

Thanks for developing jsdeferred!

Franz

@edvakf
Copy link
Collaborator

edvakf commented Jan 10, 2011

To make my code even shorter, I like to register my custom request/response handler as Deferred shorthand function.

You can use Deferred.register

  • how can I "pass on" the user_id obtained in the first request to parameters of the second request?

The easiest way is to bring the user_id to the outer scope.

  • How can I differentiate between parallell and sequential execution of the makeRequest- function?

I don't get your question. the "next" chain is always serial. Within the chain, you can use "parallel" if you want.

  • How can I implement error handling proberly? (e.g. request1 gives an error response --> chain should stop and user should be notified of bad response)

Put "error" in your chain, which handles any error occurs prior to that. If there is an error at "A" below, then B won't be executed but "C" and "D" will be executed.

next(A).next(B).error(C).next(D);

You can do something like this. (I haven't run this, so excuse me if there is a mistake)

function makeRequest(method, params) {
  $.extend(params,{method: method, api_key: 123});
  var url = $.param('http://api.example.com', params);
  return $.get(url);
}
Deferred.register('makeRequest', makeRequest);

var user_id;
makeRequest('getIdForUsername', {username:'dummy'})
.next(function(s){
  user_id = s;
})
.error(function(err){
  // error in request 1
})
.makeRequest('getUserStatus', {user_id:user_id})
.next(function(userstatus){
  //generate HTML for user status
})
.error(function(err){
  //  error in request 2
});

@fbuchinger
Copy link
Author

Thanks for your hints! I'm thinking about registering a second function that is responsible for storing the responses, so that I could write something like

Deferred.register('makeRequest', makeRequest);
Deferred.register('saveResponse', saveResponse);

makeRequest('getIdForUsername', {username:'dummy'})
.saveResponse('user_id')

I suppose saveResponse must return some function that takes care of storing the value: (?)
var savedKeys = {};
function saveResponse(key){
var key = key;
return function (s){
savedKeys[key] = s.key
}
}

Is there a way to "break" (stop executing) the chain programmatically? E.g. if the user enters a bogus username, I don't want the subsequent requests to be executed.

@edvakf
Copy link
Collaborator

edvakf commented Jan 11, 2011

At the moment there is no way for a registered function to receive an argument from the prior chain. Current implementation of Deferred.register is like this.

Deferred.register = function (name, fun) {
  this.prototype[name] = function () {
    var a = arguments;
    return this.next(function () {
      return fun.apply(this, a);
    });
  };
};

You see where there is "return this.next(function () {", this function should take the returned value of the chain. Unless you hack up your own "register", it's difficult.

Instead, I would just pass an anonymous function to a "next"

makeRequest('getIdForUsername', {username:'dummy'})
.next(function(user_id) {
  return saveResponse(user_id)
})
.next(...)

If saveResponse returns a deferred object, then the chain continues after the saveResponse. (otherwise the chain continues without waiting for asynchronous saveResponse)

Is there a way to "break" (stop executing) the chain programmatically? E.g. if the user enters a bogus username, I don't want the subsequent requests to be executed.

Maybe write "error" only at the end of the chain?

next(function() {
  throw 'INVALID_USERNAME';
})
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.next(function(){}) // not executed
.error(function(err) {
  if (err === 'INVALID_USERNAME')
    // alert
});

There is also Deferred.prototype.cancel, but I've never used it before. Looks like it's not suitable for this case. (not sure)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants