Make sequential fadeIn() promises more manageable
You don't actually need promises for this one. Here's an overly simplified version that takes advantage of the fact that you can call the containing function by a given name.

// Let's turn a jQuery set to an array coz it doesn't have shift, which we'll use
var liArray = $('li').hide().get();

$('input').click(function handle(){
  // Unqueue one from the set and fade it in. Note that shift() alters the array so
  // the next time we call it, the second one is in front of the queue. Also wrapping
  // what we shifted with jQuery because get() returns an array of DOM elements of 
  // the jQuery set
  var li = $(liArray.shift());

  // If we shifted out nothing, then that's the end of this.
  if(!li) return;

  // Set the callback of the fadeIn to the same function. That way, if the animation
  // completes, then it fires again.
  li.fadeIn(handle);
});


If the idea is to teach promises, then the following might be better. Here's an interesting approach where we use Array.prototype.reduce to carry over a dummy deferred, attach the handlers and kick it off, starting the fadeIn process.

var liArray = $('li').hide().get();

// So here we create a deferred object and during its creation, fade in the element.
// When the animation completes, it calls on `deferred.resolve` which resolves the
// fade promise.
function fade(item) {
  return $.Deferred(function (deferred) {
    $(item).fadeIn(deferred.resolve);
  }).promise();
}

// Here we use reduce to attach a handler for each item as well as allow us to carry
// over a value to the next iteration - the result value of `then()`.
function reducer(promise, item) {
  return promise.then(function () {
    return fade(item);
  });
}


// Here we create a dummy promise which allows our reducer to attach the handlers. 
// Then we use reduce to attach a handler for each item on the promise and then kick
// of the whole operation by resolving the dummy promise.
$('input').click(function handle() {
  var root = $.Deferred();
  liArray.reduce(reducer, root.promise());
  root.resolve();
});


Both examples assume liArray is an array containing li elements, whether dynamically generated or just fetched from the page, either way it doesn't matter as long as they're already rendered. Also went for an array instead of a jQuery object because array operations like shift() and reduce() are very handy.