Promises

und andere Versprechungen

Stefan von der Krone

Das Problem

  • Synchroner vs. Asynchroner Code
  • Callbacks

Das Problem

Synchroner Code

function getUser(name) {
    var sql = 'SELECT * FROM users WHERE name=?';
    var user = query(sql, name); // <- blocking
    if (!user) throw new Error('no user!');
    return user;
}

Das Problem

Asynchroner Code

function getUser(name, callback) {
    var sql = 'SELECT * FROM users WHERE name=?'
    query(sql, name, function (error, user) {
        if (error) {
            callback(error);
        } else if (!user) {
            callback(new Error('no user!'));
        } else {
            callback(null, user);
        }
    });
};

Das Problem

Wie werden Fehler behandelt?

Global State Var(s)?

The NodeJS Way?

Wrapper?

fs.readFile(
  filename, 'utf8', function (err, res){
    if (err) return callback(err);
    callback(null, JSON.parse(res));
  }
);
var res, err;
function onFinished() {
  if (err) { /* handle error */ }
  else { /* handle result */ }
}
// ... do awesome stuff with 'onFinished'
// as final callback ...
doAwesomeStuffWithManyInnerCallbacks( {
  onComplete: function( result ) {
    // handle result
  },
  onError: function( error ) {
    // handle error
  }
} );

Das Problem

Wie werden Fehler behandelt?

function getUser(name, callback) {
  var sql = 'SELECT * FROM users WHERE name=?';
  query(sql, nome, function (error, user) {
    // Nobody can catch this error!
    if (error) throw error; // <- BAD
    // Nobody gets this return value!
    return user;
  });
}

Das Problem

Zusammenfassend

  • kein throw
  • kein return
  • kein Stack
  • aber non-blocking :)

Quo Vadis?

Die Lösung

Promises / Futures

Ein Future oder ein Promise bezeichnet in der Programmierung einen Platzhalter (Proxy) für ein Ergebnis, das noch nicht bekannt ist, meist weil seine Berechnung noch nicht abgeschlossen ist. (Wikipedia)

Der veränderte Code

Die Lösung

getUser('sdk', function (error, user) {
  // ...
});

// becomes

getUser('sdk')
  .then(function (user) {
    // ...
  }, function (error) {
    // ...
  });
try {
  var user = getUser('sdk');
  if (!user)
    throw new Error('no user!');
  var name = user.name;
} catch (e) { /* handle error */ }

// becomes

getUser('sdk')
    .then(function (user) {
        return user.name;
    })
    .then(function(name) {
        // do some awesome stuff
    }, function(reason) {
        // handle error
    });

Sequenzierung

Die Lösung

var user = getUser('thunderkrown');
var tweets = getNewTweets(user);
updateTimeline(tweets);

// using callbacks

getUser('thunderkrown', function (user) {
  getNewTweets(user, function (tweets) {
    updateTimeline(tweets);
  });
});

// using promises

getUser('thunderkrown')
    .then(getNewTweets)
    .then(updateTimeline);
var user = getUser('thunderkrown');
var tweets = getNewTweets(user);
updateTimeline(tweets);

// using callbacks

getUser('thunderkrown', function (user) {
  getNewTweets(user, function (tweets) {
    updateTimeline(tweets);
  });
});

// using promises

getUser('thunderkrown')
    .then(getNewTweets)
    .then(updateTimeline, onError);

Warum Promises?

Wer setzt's ein?

  • Ich
  • Ember
  • jQuery (so halb)
  • AngularJS
Q($.ajax(/* ... */));

Promises in Angular

  • implementiert Q-Promises in einer lite-version als $q
  • wird als Service bereitgestellt
  • auch in $http und $resource integriert

Wie wird's benutzt?

Promises in Angular

var deferred = $q.defer();

// bei Erfolg
deferred.resolve( result );

// bei Fehler
deferred.reject( error );

return deferred.promise;
return $q(function(resolve, reject) {
  // bei Erfolg
  resolve( result );
  // bei Fehler
  reject( error );
});

seit Angular 1.3

Ein Beispiel

Promises in Angular

App.config( function( $stateProvider, $urlRouterProvider ) {
  $stateProvider
    .state( "someState", {
      url: "/some-state",
      templateUrl: "some-state.html",
      controller: function($scope, data) {},
      resolve: {
        data: function() {
          // returns a ($q-)Promise
          return loadData()
        }
      }
    } );
} );

Aber Achtung!!!

Promises in Angular

  • Immer Promise mit resolve/reject auflösen!!!

Theorie-Exkurs

Promises sind monadische Daten-Strukturen

Theorie-Exkurs

Was ist eine Monade?

~Abstrakter Datentyp, der einen Ausdruck in einen Kontext kapselt.~

  • Einheitsfunktion ( unit / return / new Promise)
  • bind-Operator (>>= / .bind() / .then())

Wie sieht eine Monade aus?

Promises und andere Versprechungen

By Stefan Von Der Krone

Promises und andere Versprechungen

  • 488