4 ms·
Twisted (the asynchronous framework for Python) has an equivalent structure called a "Deferred": http://twistedmatrix.com/documents/current/core/howto/defe
by thristian 14y ago
Twisted (the asynchronous framework for Python) has an equivalent structure called a "Deferred":
http://twistedmatrix.com/documents/current/core/howto/defer.html
It's very similar to the "Promises/A" system described in the article, except that it has different method names (instead of .then(), it has the more prosaic .addCallback() and .addErrback()), and you generally have only one of them (instead of the callback-adding function returning a new, fresh, clean instance). Deferreds have the same ideal of composability, and the same mapping to 'try/except' statements in synchronous code.
However, there's one particularly handy thing Deferreds do that I don't see described in the article: when "fulfilledHandler" gets called, it can return a value which gets passed to the next callback in the chain, _or it can return a Deferred_, in which case the callback chain pauses until the new Deferred fires and produces a value, at which point the original Deferred picks up and carries on.
This comes in very handy for things like this:
def getReservedBooksForUser(username):
# Look up the auth token for the library service in the DB
authTokenDeferred = db.runQuery("""
SELECT authToken
FROM users
WHERE username = ?
""", (username,))
# We know the DB result can only have one row and one column.
authTokenDeferred.addCallback(lambda resultset: resultset[0][0])
# When we have the auth token, use it when querying the library
# service.
authTokenDeferred.addCallback(
lambda authToken: web.getPage(
"http://library/books?authToken=%s&user=%s&format=JSON"
% (authToken, request["username"])
)
)
# Extract the list of books from the returned document.
authTokenDeferred.addCallback(
lambda page: json.loads(page)['books']
)
return authTokenDeferred
Note that the second callback (the web.getPage() one) is immediately called with the results of the first callback (the resultset-unpacking one), because the first callback returned an ordinary value.
However, the third callback (the JSON-unpacking one) is not called with the Deferred returned by the second callback - instead, the callback chain is paused while we wait for the second callback's Deferred to fire, then that result is passed to the third callback.
Is this kind of thing supported by JS Promises, too?
- wycats 14y agoGood promises libraries (like Q and my RSVP.js: https://github.com/tildeio/rsvp.js https://github.com/tildeio/rsvp.js) absolutely do support this. Check out https://github.com/domenic/promise-tests/blob/master/lib/tests/returning-a-promise.js https://github.com/domenic/promise-tests/blob/master/lib/tes... for the tests for this behavior, which most promises libraries (but not jQuery) pass.
- domenicd 14y agoAs wycats says, this indeed supported by good JS promises. I talked a bit more about the situation in my promise-tests documentation: https://github.com/domenic/promise-tests#returning-a-promise-from-a-handler https://github.com/domenic/promise-tests#returning-a-promise... Unfortunately Promises/A omits this, so I didn't address it directly, although I did sneak it into the example code with the `return expandUrlUsingTwitterApi(mostRecentShortUrl);` line.
- klibertp 14y agoWell, it is, at least in good implementations. One that I know about and use regularly is somewhat dated, but "feature complete" and as Pythonic as it gets: MochiKit and it's Deffereds: http://mochi.github.com/mochikit/doc/html/MochiKit/Async.html#fn-deferred http://mochi.github.com/mochikit/doc/html/MochiKit/Async.htm...