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/12.1.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/12.1.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
23 asynchronous programming approach. First, asynchronous code is
24 frequently (if not always) concerned with some data (in Python, an
25 object) which is not yet available but which probably will be
26 soon. Asynchronous code needs a way to define what will be done to the
27 object once it does exist. It also needs a way to define how to handle
28 errors in the creation or acquisition of that object. These two needs
29 are satisfied by the <i>callbacks</i> and <i>errbacks</i> of
30 a <code>Deferred</code>. Callbacks are added to
31 a <code>Deferred</code> with <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.addCallback.html" title="twisted.internet.defer.Deferred.addCallback">Deferred.addCallback</a></code>; errbacks
32 are added with <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.addErrback.html" title="twisted.internet.defer.Deferred.addErrback">Deferred.addErrback</a></code>. When the
33 object finally does exist, it is passed to <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.callback.html" title="twisted.internet.defer.Deferred.callback">Deferred.callback</a></code> which passes it
34 on to the callback added with <code>addCallback</code>. Similarly, if
35 an error occurs, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.defer.Deferred.errback.html" title="twisted.internet.defer.Deferred.errback">Deferred.errback</a></code> is called and
36 the error is passed along to the errback added
37 with <code>addErrback</code>. Second, the events that make
38 asynchronous code actually work often take many different,
39 incompatible forms. <code>Deferred</code> acts as the uniform
40 interface which lets different parts of an asynchronous application
41 interact and isolates them from implementation details they shouldn't
42 be concerned with.</p>
44 <p>That's almost all there is to <code>Deferred</code>. To solidify your new
45 understanding, now consider this rewritten version
46 of <code>DelayedResource</code> which uses a <code>Deferred</code>-based delay
47 API. It does exactly the same thing as the <a href="asynchronous.html" shape="rect">previous
48 example</a>. Only the implementation is different.</p>
50 <p>First, the example must import that new API that was just mentioned, <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code>:</p>
52 <pre class="python"><p class="py-linenumber">1
53 </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>
56 <p>Next, all the other imports (these are the same as last time):</p>
58 <pre class="python"><p class="py-linenumber">1
61 </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>
62 <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>
63 <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>
66 <p>With the imports done, here's the first part of
67 the <code>DelayedResource</code> implementation. Again, this part of
68 the code is identical to the previous version:</p>
70 <pre class="python"><p class="py-linenumber">1
74 </p><span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>):
75 <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>):
76 <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"<html><body>Sorry to keep you waiting.</body></html>"</span>)
77 <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>()
80 <p>Next we need to define the render method. Here's where things
81 change a bit. Instead of using <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.interfaces.IReactorTime.callLater.html" title="twisted.internet.interfaces.IReactorTime.callLater">callLater</a></code>,
82 We're going to use <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.task.deferLater.html" title="twisted.internet.task.deferLater">deferLater</a></code> this
83 time. <code>deferLater</code> accepts a reactor, delay (in seconds, as
84 with <code>callLater</code>), and a function to call after the delay
85 to produce that elusive object discussed in the description
86 of <code>Deferred</code>s. We're also going to
87 use <code>_delayedRender</code> as the callback to add to
88 the <code>Deferred</code> returned by <code>deferLater</code>. Since
89 it expects the request object as an argument, we're going to set up
90 the <code>deferLater</code> call to return a <code>Deferred</code>
91 which has the request object as its result.</p>
93 <pre class="python"><p class="py-linenumber">1
97 <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>):
98 <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>)
101 <p>The <code>Deferred</code> referenced by <code>d</code> now needs to
102 have the <code>_delayedRender</code> callback added to it. Once this
103 is done, <code>_delayedRender</code> will be called with the result
104 of <code>d</code> (which will be <code>request</code>, of course — the
105 result of <code>(lambda: request)()</code>).</p>
107 <pre class="python"><p class="py-linenumber">1
110 <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>)
113 <p>Finally, the render method still needs to return <code>NOT_DONE_YET</code>,
114 for exactly the same reasons as it did in the previous version of the
117 <pre class="python"><p class="py-linenumber">1
120 <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span>
123 <p>And with that, <code>DelayedResource</code> is now implemented
124 based on a <code>Deferred</code>. The example still isn't very
125 realistic, but remember that since <code>Deferred</code>s offer a
126 uniform interface to many different asynchronous event sources, this
127 code now resembles a real application even more closely; you could
128 easily replace <code>deferLater</code> with
129 another <code>Deferred</code>-returning API and suddenly you might
130 have a resource that does something useful.</p>
132 <p>Finally, here's the complete, uninterrupted example source, as an rpy script:</p>
134 <pre class="python"><p class="py-linenumber"> 1
150 </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>
151 <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>
152 <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>
153 <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>
155 <span class="py-src-keyword">class</span> <span class="py-src-identifier">DelayedResource</span>(<span class="py-src-parameter">Resource</span>):
156 <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>):
157 <span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>(<span class="py-src-string">"<html><body>Sorry to keep you waiting.</body></html>"</span>)
158 <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>()
160 <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>):
161 <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>)
162 <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>)
163 <span class="py-src-keyword">return</span> <span class="py-src-variable">NOT_DONE_YET</span>
165 <span class="py-src-variable">resource</span> = <span class="py-src-variable">DelayedResource</span>()
170 <p><a href="../index.html">Index</a></p>
171 <span class="version">Version: 12.1.0</span>