Meet.js promises
-
Upload
krzychukula -
Category
Documents
-
view
153 -
download
3
Transcript of Meet.js promises
Promises, Promises
@krzychukulakrzychukula.blogspot.com
Beware
● Code examples inspired by: Q.js
● Mixing polish and english
● May be complately wrong
● 20min is not enough!
The Pyramid of Doom
How async code looks like?
function onInitFs(fs) {
fs.root.getFile('foo.txt', {}, function(fileEntry) {
}, errorHandler);
}
function onInitFs(fs) {
fs.root.getFile('foo.txt', {}, function(fileEntry) {
fileEntry.file(function(file) { }, errorHandler);
}, errorHandler);
}
function onInitFs(fs) {
fs.root.getFile('foo.txt', {}, function(fileEntry) {
fileEntry.file(function(file) { var reader = new FileReader();
reader.onloadend = function(e) { var txtArea = document.createElement('textarea'); txtArea.value = this.result; document.body.appendChild(txtArea); };
reader.readAsText(file); }, errorHandler);
}, errorHandler);
}
function onInitFs(fs) {
fs.root.getFile('foo.txt', {}, function(fileEntry) {
fileEntry.file(function(file) { var reader = new FileReader();
reader.onloadend = function(e) { function onInitFs(fs) {
fs.root.getFile('foo.txt', {}, function(fileEntry) {
fileEntry.file(function(file) { var reader = new FileReader();
reader.onloadend = function(e) { var txtArea = document.createElement('textarea'); txtArea.value = this.result; document.body.appendChild(txtArea); };
reader.readAsText(file); }, errorHandler);
}, errorHandler);};
reader.readAsText(file); }, errorHandler);
}, errorHandler);
}
JS without Promises
Nicer abstraction on File API
readFoo(success, error)
Write test to check read/write
writeFoo(function(){
readFoo(function(text){
expect(text).toBe('foo');
}, error)
}, error)
writeFoo(function(){
readFoo(function(text){
expect(text).toBe('foo');
}, error)
}, error)
Start again with promises
writeFoo()//==> returns promise
writeFoo().done(success, error)
Not enough
writeFoo().done(function(){
readFoo().done(function(text){
expect(text).toBe('foo');
}, error)
}, error)
Promises
Let's learn it!
var promise = writeFoo()
Promise what it is?
Object
Promise
With State
Promise state
Subscribe to state changes
Promise
then
donefail
State
Promise
pending
resolved
rejected
state
Subscribe to state
done(success, error)
resolved rejected
Just like done*
then(success, error)
resolved rejected
Only fail handler
fail(error)
resolved rejected
See it in practice
var promise = writeFoo();
promise.done(success, error)
Many listeners
You can attach listeners to it
var promise = writeFoo()
promise.done(success, error)
Many listeners for one promise!
var promise = writeFoo()
promise.done(log, logError)
promise.done(updateStats, error)
promise.done(displayInfo, displayError)
Callback
writeFoo(funciton(data){
log(data);
updateStats(data);
displayInfo(data);
}, error)
Many listeners for one promise!
function writeFooAndLog(){var promise = writeFoo()promise.done(log, error)return promise;
}
var promise = writeFooAndLog();
promise.done(successDialog, errorDialog)
Promise lifetime
Attach listeners even when it's done!
var promise = readFoo()
promise.done(log, error)
==> resolves with cache...
You know, order matters!
var img = new Image();
img.src = "sprite.png";
img.onload = function(){ //never called
}
Promise is persistent
What if...
var img = new Image();
var promise = img.load("sprite.png");
promise.done(function(){ })
Attach listeners even when it's done!
var promise = readFoo()
promise.done(log, error)
==> resolves with cache... promise.done(updateStats, error)promise.done(displayInfo, error)
The same is true for fails
var promise = writeFoo()
promise.done(log)
promise.fail(revertTransaction)
promise.fail(logError)
Before we go deeper
Promise can change state only once.
Chains
jQuery API example
$('widget')
$('widget').addClass('important')
$('widget').addClass('important').show()
$('widget').addClass('important').show().find('h1')
Chaining
$('widget').addClass('important').show().find('h1').text('Special Offers')
Then
Similar to done
.done(asyncSuccess, error)
.then(asyncSuccess, error)
Difference
.done(asyncSuccess, error)//==> undefined
.then(asyncSuccess, error)//==> promise
Create chains for async
promise.then(asyncSuccess, error).then(syncSuccess2, error2)
Then always returns new promise
promise.then(success, error).then(success2, error2)//==> promise
Then and errors!
promise.then(success , error).then(success2 , error2).then(success3 , error3).then(success4, error4);
* not in jQuery
Then and errors!
promise.then(succes).then(success2).then(success3).then(success4, fail);
So 'then' is a better 'done'
then > done
* at least I thinked so...
Let's fix this test example
The one with pyramid
writeFoo().done(function(){
readFoo().done(function(text){
expect(text).toBe('foo');
}, error)
}, error)
But start from scratch.
writeFoo()
writeFoo().then(readFoo)
writeFoo().then(readFoo).then(function(text){
//==> content of foo file}, error);
Final Test Example*
writeFoo().then(readFoo).then(function(text){
expect(text).toBe('foo');}, fail);
Troubles
When I was starting
I've put promises everywhere!
I've used then - because it's better
I got some
Broken scripts
No errors in console
WAT!
Time for debugger...
Reason: Stupid typo
then(showLenght)
then(showLength)
but wait...
when in trouble
Promises considered harmful!
Q.js Readme
return foo().then(
function (value) { throw new Error("Can't bar.");
},function (error) { // We only get here if "foo" fails}
);
Error handler AFTER callback
return foo().then(function (value) { throw new Error("Can't bar.");}).fail(function (error) { // We get here with any callback error});
Why?
.then()//=> promise
1: Then always returns promise
Why?
.then()//=> promise
1: Then always returns promise2: Promise catches all errors
Why?
.then()//=> promise
1: Then always returns promise2: Promise catches all errors3: And passes them to the last promise
fail fast
writeFoo().then(readFoo).then(function(text){
expect(text).toBe('foo');}, fail).done();//==>undefined
So we can fix test example
writeFoo().then(readFoo).then(function(text){
expect(text).toBe('foo');}, fail);//==> promise
Done! :)
writeFoo().then(readFoo).done(function(text){
expect(text).toBe('foo');}, fail);//==>undefined
Deferred
Deferred
How can I change state of promise?
Deferred Promise
Deferred Promise
READONLY
Master of promise
Deferred Promise
READONLY
resolve reject
Show me the code
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
Create Deferred
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
Return promise from deferred
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
success == resolve
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
error == reject
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
Wrap it in function
function getFoo(){var deferred = Q.defer();FS.readFile("foo.txt", function (error, text) { if (error) { deferred.reject(new Error(error)); } else { deferred.resolve(text); }});return deferred.promise;
}
getFoo().then(joinLines).then(displayContent, showError).done();
All
3 simultaneous calls
3 ajax calls at once
Without pyramid
without call counting
var ajaxCalls = 3;
success: function(){if(--ajaxCalls == 0) letUserKnow
var promise1 = $.ajax(one);var promise2 = $.ajax(two);var promise3 = $.ajax(three);
Q.all([promise1, promise2, promise3]).done(letUserKnow);
var promise1 = $.ajax();var promise2 = $.ajax();var promise3 = $.ajax();
Q.all([promise1, promise2, promise3]).done(letUserKnow)
var promise1 = $.ajax();var promise2 = $.ajax();var promise3 = $.ajax();
Q.all([promise1, promise2, promise3]).done(letUserKnow);
var promise1 = $.ajax();var promise2 = $.ajax();var promise3 = $.ajax();
Q.all([promise1, promise2, promise3]).done(letUserKnow);
Summary
InitFs()
.then(getFile('foo.txt', {}))
.then(openFile)
.then(readAsText)
.done(displayInTextarea, errorHandler)
Many listeners for one promise!
var promise = writeFoo()
promise.done(log)promise.done(updateStats)
promise.fail(logError)promise.fail(displayError)
You can chain promises with 'then'
promise.then(succes).then(success2).then(success3).then(success4, fail);
When You See No Errors
.done()
Only 2 slides till the end ;)
Thanks for listening!
Instead of QA
Async JavaScript by Trevor Burnham
github.com/medikoo/deferredwww.medikoo.com/asynchronous-javascript/ by Mariusz Nowak
github.com/kriskowal/q
The end
Let me know how I can be better:
@krzychukula