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?
- Standard in ES6 Harmony
- Future proofed
- State Machine
- Es gibt eine Spezifikation (https://promisesaplus.com/)
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