1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: Asynchronous Responses (via Deferred)</title>
4
<link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">Asynchronous Responses (via Deferred)</h1>
9
<div class="toc"><ol/></div>
13
<p>The previous example had a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.resource.Resource.html" title="twisted.web.resource.Resource">Resource</a></code> that generates its response
14
asynchronously rather than immediately upon the call to its render
15
method. Though it was a useful demonstration of the <code>NOT_DONE_YET</code>
16
feature of Twisted Web, the example didn't reflect what a realistic application
17
might want to do. This example introduces <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>, the Twisted class which is used
18
to provide a uniform interface to many asynchronous events, and shows you an
19
example of using a <code>Deferred</code>-returning API to generate an
20
asynchronous response to a request in Twisted Web.</p>
22
<p><code>Deferred</code> is the result of two consequences of the asynchronous
23
programming approach. First, asynchronous code is frequently (if not always)
24
concerned with some data (in Python, an object) which is not yet available but
25
which probably will be soon. Asynchronous code needs a way to define what will
26
be done to the object once it does exist. It also needs a way to define how to
27
handle errors in the creation or acquisition of that object. These two needs are
28
satisfied by the <i>callbacks</i> and <i>errbacks</i> of a
29
<code>Deferred</code>. Callbacks are added to a <code>Deferred</code> with <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.addCallback.html" title="twisted.internet.defer.Deferred.addCallback">Deferred.addCallback</a></code>; errbacks
30
are added with <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.addErrback.html" title="twisted.internet.defer.Deferred.addErrback">Deferred.addErrback</a></code>. When the object
31
finally does exist, it is passed to <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.callback.html" title="twisted.internet.defer.Deferred.callback">Deferred.callback</a></code> which passes it on to the
32
callback added with <code>addCallback</code>. Similarly, if an error occurs,
33
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.errback.html" title="twisted.internet.defer.Deferred.errback">Deferred.errback</a></code> is
34
called and the error is passed along to the errback added with
35
<code>addErrback</code>. Second, the events that make asynchronous code actually
36
work often take many different, incompatible forms. <code>Deferred</code> acts
37
as the uniform interface which lets different parts of an asynchronous
38
application interact and isolates them from implementation details they
39
shouldn't be concerned with.</p>
41
<p>That's almost all there is to Deferred. To solidify your new understanding,
42
now consider this rewritten version of DelayedResource which uses a
43
Deferred-based delay API. It does exactly the same thing as the <a href="asynchronous.html" shape="rect">previous example</a>. Only the implementation is
46
<p>First, the example must import that new API that was just mentioned, <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code>:</p>
48
<pre class="python"><p class="py-linenumber">1
49
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">task</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">deferLater</span>
52
<p>Next, all the other imports (these are the same as last time):</p>
54
<pre class="python"><p class="py-linenumber">1
57
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span>
58
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span>
59
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
62
<p>With the imports done, here's the first part of the
63
<code>DelayedResource</code> implementation. Again, this part of the code is
64
identical to the previous version:</p>
66
<pre class="python"><p class="py-linenumber">1
70
</p><span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>):
71
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
72
<span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>)
73
<span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>()
76
<p>Next we need to define the render method. Here's where things change a
77
bit. Instead of using <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IReactorTime.callLater.html" title="twisted.internet.interfaces.IReactorTime.callLater">callLater</a></code>, We're going to
78
use <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code> this
79
time. <code>deferLater</code> accepts a reactor, delay (in seconds, as with
80
<code>callLater</code>), and a function to call after the delay to produce that
81
elusive object discussed in the description of Deferreds. We're also going to
82
use <code>_delayedRender</code> as the callback to add to the
83
<code>Deferred</code> returned by <code>deferLater</code>. Since it expects the
84
request object as an argument, we're going to set up the <code>deferLater</code>
85
call to return a <code>Deferred</code> which has the request object as its
88
<pre class="python"><p class="py-linenumber">1
90
</p><span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
91
<span class="py-src-variable">d</span> = <span class="py-src-variable">deferLater</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-number">5</span>, <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">request</span>)
94
<p>The <code>Deferred</code> referenced by <code>d</code> now needs to have the
95
<code>_delayedRender</code> callback added to it. Once this is done,
96
<code>_delayedRender</code> will be called with the result of <code>d</code>
97
(which will be <code>request</code>, of course — the result of <code>(lambda:
98
request)()</code>).</p>
100
<pre class="python"><p class="py-linenumber">1
101
</p><span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>)
104
<p>Finally, the render method still needs to return <code>NOT_DONE_YET</code>,
105
for exactly the same reasons as it did in the previous version of the
108
<pre class="python"><p class="py-linenumber">1
109
</p><span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span>
112
<p>And with that, <code>DelayedResource</code> is now implemented based on a
113
<code>Deferred</code>. The example still isn't very realistic, but remember that
114
since Deferreds offer a uniform interface to many different asynchronous event
115
sources, this code now resembles a real application even more closely; you could
116
easily replace <code>deferLater</code> with another
117
<code>Deferred</code>-returning API and suddenly you might have a resource that
118
does something useful.</p>
120
<p>Finally, here's the complete, uninterrupted example source, as an rpy script:</p>
122
<pre class="python"><p class="py-linenumber"> 1
138
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">task</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">deferLater</span>
139
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span>
140
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">NOT_DONE_YET</span>
141
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
143
<span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>):
144
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_delayedRender</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
145
<span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"Sorry to keep you waiting."</span>)
146
<span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>()
148
<span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
149
<span class="py-src-variable">d</span> = <span class="py-src-variable">deferLater</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-number">5</span>, <span class="py-src-keyword">lambda</span>: <span class="py-src-variable">request</span>)
150
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_delayedRender</span>)
151
<span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span>
153
<span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>()
158
<p><a href="../index.html">Index</a></p>
159
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'