Skip to content

Latest commit

 

History

History
500 lines (364 loc) · 8.37 KB

slides.md

File metadata and controls

500 lines (364 loc) · 8.37 KB

Is this right?

var input = //...
try {
	var result = computeResult(input);
	displayResult(result);
} catch(e) {
	displayError(e);
}

Let's talk about

Bug http://www.flickr.com/photos/zanehollingsworth/5701745474


Is this right?

computeResult(input, function(e, result) {
	if(e) {
		displayError(e);
	} else {
		displayResult(result);
	}
});

Fixed

computeResult(input, function(e, result) {
	if(e) {
		displayError(e);
	} else {
		try {
			displayResult(result);
		} catch(e) {
			displayError(e);
		}
	}
});

Is this right?

function getTheResult() {
    try {
        return thisMightFail();
    } catch(e) {
        return recoverFromFailure(e);
    } finally {
        alwaysCleanup();
    }
}

Is this right?

function getTheResult(nodeCallback) {
    thisMightFail(function(error, result) {
        if(error) {
            try {
                result = recoverFromFailure(error);
                error = null;
            } catch(e) {
                error = e;
            }
        }

        alwaysCleanup();

        // If error is still falsey, we've succeeded
        nodeCallback(error, result);
    });
}

Is this right?

function getTheResult(onSuccess, onFailure) {
    thisMightFail(
        function(result) {
            try {
                onSuccess(result);
            } catch(e) {
                onFailure(e);
            } finally {
            	alwaysCleanup();
        	}
        },
        function(error) {
            var recoveryResult;
            try {
                recoveryResult = recoverFromFailure(error);
                error = null;
            } catch(e) {
                error = e;
            }

            try {
                alwaysCleanup();
            } catch(e) {
                error = e;
            }

            if(error) {
                onFailure(error);
            } else {
                onSuccess(recoveryResult);
            }
        }
    );
}

WAT http://www.flickr.com/photos/timsnell/7986996932


The problem

  • Impossible to reason about and maintain
  • Recreate flow control and error handling machinery

Promises: The solution

Promises give you async versions of return and throw.

They let you take back the call stack.


Promises

computeResult(input)
	.then(displayResult)
	.otherwise(displayError);

http://know.cujojs.com/tutorials/async/mastering-async-error-handling-with-promises


Promises

function getTheResult() {
    return thisMightFail()
        .otherwise(recoverFromFailure);
        .ensure(alwaysCleanup);
}

http://know.cujojs.com/tutorials/async/mastering-async-error-handling-with-promises


Promises

  • MultiLisp, Act 1, Prolog concurrent logic variables, Joule and E promises, java.util.concurrent.Future, Python Twisted deferred, Dojo Deferred, F# Async<T>, .NET Task<T>, C++11 std::future and std::promise, Dart Future<T>, Scala Future
  • Javascript Promises/A+

Let's talk about

Tardis http://www.flickr.com/photos/rooners/4415074931


var when = require('when');

when.reduce(
	when.map($.get('/users'), getTags), groupTags)
	.then(displayTags);

var nodefn = require('when/node/function');
var fs = require('fs');
var readFile = nodefn.lift(fs.readFile);
var writeFile = nodefn.lift(fs.writeFile);

// This all happens async:
writeFile('out.txt', readFile('in.txt'));

Let's talk about

The future

Head explosion


function* someNumbers() {
  yield 1;
  yield 2;
  yield 3;
}

var iterator = someNumbers();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { done: true }

// thisMightFail, recoverFromFailure, and
// alwaysCleanup are ASYNC!
var zomg = promisedGenerator(function* () {
	var result;

    try {
        result = yield thisMightFail();
    } catch(e) {
        result = yield recoverFromFailure(e);
    } finally {
        yield alwaysCleanup();
    }

    yield result;
});

var result = zomg();

// ES5 (and ES3)
Users.get('brian')
	.then(function(user) {
		return user.fetchBlogPosts();
	})
	.then(function(posts) {
		return posts.toHtml();
	})
	.then(function(html) {
		container.innerHTML = html;
	});
// ES6
container.innerHTML = yield Users.brian.posts.toHtml();

Let's talk about

Cybermen! http://www.flickr.com/photos/rooners/4652345494


Promise aren't perfect

  • VMs/platforms aren't promise-aware
  • disjoint or missing stack traces
  • when.js and Q can trap and report unhandled rejections
    • and stitch stack traces

Common mistakes

  • return something!!
  • Don't break the chain
  • rejection handlers work like catch, if you don't "rethrow", the error is considered "handled" and won't propagate
    • This consistency is a good thing

Code smells

// You sly dog:
// If doSomething fails, no one will ever know
promise.then(doSomething);
return promise;
// You probably meant:
return promise.then(doSomething);

Code smells

// Oops, you returned `undefined` which
// turns this rejection into a success
return promise.otherwise(function(e) {
	logError(e);
});
// Preferably, let the error be handled higher
// in the call stack, like exceptions!
return promise;
// But if you must:
return promise.otherwise(function(e) {
	logError(e);
	throw e;
});

Let's talk about

Aristotle

http://www.flickr.com/photos/pelegrino/6884873348


Aristotle: Poetics

  • Exposition
  • Inciting incident
  • Rising action
  • Climax

The Promises/A+ Drama


Exposition

Promises/A

http://wiki.commonjs.org/wiki/Promises/A


Inciting incident

Deceit!

jQuery Deferred Deceit

https://github.com/jquery/jquery/commit/a41f2406748e3113751ab1e5b5d990d9144123fc


Rising action

Complications!

Ember.Deferred Shenanigans

emberjs/ember.js#1406


Rising action

Conflict!

Domenic's You're Missing the Point of Promises

https://gist.github.com/domenic/3889970


Rising action

Heroics!

Domenic's Promises/A Test Suite

https://github.com/domenic/promise-tests


Rising action

Action!

Brian's original Promises/A+ proposal gist

https://gist.github.com/briancavalier/eb5fc157825a170c9957


Boom!

Explosions!

Promises/A+

http://promisesaplus.com


Promises/A+ test suite

Promises/A+ Test Suite

https://github.com/promises-aplus/promises-tests


Promises/A+ stats

  • 33 verified implementations, more every week
  • Several "inspired by Promises/A+" in other languages

DOM Promises

DOM Promises

http://dom.spec.whatwg.org/#promises


ES7

Slated to have Promises as a language feature

Happy!


Wait, what?!?

How did all this happen in about 6 months


Aristotle: Poetics

  • Plot
  • Character
  • Theme
  • Diction
  • Music & spectacle (setting)

Plot

Sane JavaScript asynchrony


Character

Strong and cooperative community of implementors and users


Theme

Extend the web forward

http://yehudakatz.com/2013/05/21/extend-the-web-forward/


Diction

Minimal spec for sanity and interoperability


Setting

Github


Promises/A+

An open standard for sound, interoperable JavaScript promises—by implementers, for implementers.


Thanks!

@briancavalier

SpringJS @ Pivotal

cujoJS co-founder

promisesaplus.com co-editor

@promisesaplus


Credits