What is the most concise way to use jQuery lazy pipe?

I am developing a javascript API that completes my REST API. Usually I want to avoid a lot of detailed and confusing nested callbacks and read the deferred jQuery utility.

Imagine my myLib library, which represents people’s objects and how to move between people’s objects. It has a bunch of methods, such as dad, boss, assistant, etc., which must execute an ajax request to find some data and return another related people object. But I want them to return a pending object that also has myLib methods that I can combine to write really simple simple code, like this:


 myLib('me').dad().boss().assistant(function(obj){
   alert(obj.phone); // My dad's, bosses assistants phone number
 }, function(){
   alert('No such luck);
 });

This creates a person’s self object, then the first ajax call to find my data, then uses this data to make another call to find out my parent, and then find my boss again, and then the other to get an assistant, and then finally, this is passed to my callback, and I process it. As if jQuery riveted the move methods, but asynchronously.

A function transfer at any point, but usually the last method, will be internally called when the last Pending object in the chain is allowed. The second function is the failure callback and is called if any of the pending objects in the chain are rejected.

I think I need to create a jQuery deferred object and then expand it, but not sure if this is the best way.

, API? , 100% "", "", "" ..

API, -?

+5
3

, Person . . , parent(), , . , , pipe(), .


myLib = {
  find: function(id){
    var person = new Person();
    person.promise = $.ajax(.....);
  }
};

function Person(){
}
Person.prototype.parent(){
  var person = this;
  var parent = new Person();
  var deferred = $.Deferred();
  this.promise.then(function(data){
    var promise = $.ajax({url: '/person/'+data.parent+'/json'});
    promise.done(function(obj){
      person.data = obj.data;
      deferred.resolve(node);
    });
  }, function(error){
    deferred.fail();
  });
  parent.promise = deferred.promise();
  return parent;
}

Person.prototype.get(callback){
  this.promise.then(function(data){
    this.data = data;
    callback(this);
  });
}


Usage/Test:

myLib.find('12345').get(callback);
myLib.find('12345').parent().get(callback);



0

, , :

function Person(o) {
  this.id = o.id;
  this.name = o.name;
}

Person.prototype.dad = function(done, fail) {
  var promise = $.getJSON('/people/' + this.id + '/dad').pipe(Person, null);
  promise.then(done, fail);
  return new Person.Chain(promise);  
};

Person.prototype.boss = function(done, fail) {
  var promise = $.getJSON('/people/' + this.id + '/boss').pipe(Person, null);
  promise.then(done, fail);
  return new Person.Chain(promise);  
};

Person.Chain : , getter, Person.Chain, Person.Chain "": AJAX . .

, :

Person.Chain = function(promise) {
  this.promise = promise;
};

Person.Chain.prototype.assistant = function(done, fail) {
  return this.pipe('assistant', done, fail);
};

Person.Chain.prototype.dad = function(done, fail) {
  return this.pipe('dad', done, fail);
};

Person.Chain.prototype.boss = function(done, fail) {
  return this.pipe('boss', done, fail);
};

-, Person getter. pipe:

Person.Chain.prototype.pipe = function(f, done, fail) {
  var defer = new $.Deferred();
  defer.then(done, fail);

  this.promise.pipe(function(person) {
    person[f](function(person) {
      defer.resolve(person);
    }, function() {
      defer.reject();
    });
  }, function() {
    defer.reject();
  });

  return new Person.Chain(defer.promise());
}

"" done fail ( ). , f (, , ..) Person, . , , . :

jake = new Person({id: 3, name: 'Jake'});

jake.dad().boss().assistant(function(person) {
  alert("Jake dad boss assistant is " + person.name);
});

, - , , , , . reject() , .

:

jake.dad(function(person) {
  alert('Dad is ' + person.name);
}, function() {
  alert('Dad call failed');
}).boss(function(person) {
  alert('Jake dad boss is ' + person.name);
}, function() {
  alert('One of the calls failed');
});

, . , , .

, . , , .

+2

I think you want to create a query builder where methods that add criteria (for example, "dad" and "assistant") are all connected to each other. In addition, you want you to be able to pass a callback at any time, and that means fulfilling the request.

So, I would do it like this:

function PersonQuery(personName) {
  this.criteria = [];
  criteria.push({name:personName});
}

PersonQuery.prototype.dad = function(doneCallback) {
    this.criteria.push({relationship:"dad"});
    _execute(doneCallback);
    return this;
}

PersonQuery.prototype.boss = function(doneCallback) {
    this.criteria.push({relationship:"boss"});
    _execute(doneCallback);
    return this;
}

PersonQuery.prototype.assistant = function(doneCallback) {
    this.criteria.push({relationship:"assistant"});
    _execute(doneCallback);
    return this;
}

PersonQuery.prototype._execute = function(doneCallback) {
    if (!doneCallback) {
       return;
    }
    $.ajax({"data": this.criteria}).success(function(responseData) {
       doneCallback(responseData);   
    });
}

Then, to use this, your example will become:

   new PersonQuery("me").dad().boss().assistant(function(obj) { 
    alert(obj.phone); });
+1
source

All Articles