Chaining Deferreds¶
The callbacks of Deferreds can be linked via the Deferred.chainDeferred
function. This makes it so that calling or errbacking the first deferred also
triggers the callback or errback of the second.
Functionally, this is the same as adding the callback and errback of the second deferred as a callback and errback of the first respectively.
chainDeferred
is a one-way link. Calling back the second Deferred will not
trigger the first’s callback unless the second has had its own chainDeferred
function called on the first.
When to use it¶
When you want one Deferred to trigger the callbacks of others.
How to use it¶
Below we create two deferreds: deferredGetsChained
, and
deferredMakesChain
. Then we call chainDeferred
on
deferredMakesChain
with deferredGetsChained
as an argument.
Because deferredGetsChained.callback
is now the first of
deferredMakesChain
’s callbacks, the value of deferredMakesChain
is
passed to the first callback of deferredGetsChained
, which is print
.
Because deferredGetsChained
’s callback has been triggered, it fires its
callbacks itself, resulting in it also being printed.:
from twisted.internet import defer
from twisted.trial import unittest
class ExampleTests(unittest.TestCase):
def testDeferredChaining(self):
# Create two Deferreds
deferredGetsChained = defer.Deferred()
deferredMakesChain = defer.Deferred()
# Give the chain-ee a callback
deferredGetsChained.addCallback(print, "So was I!")
# Chain the first Deferred to the second
deferredMakesChain.chainDeferred(deferredGetsChained)
# Call the first Deferred back to trigger the callback of the other
deferredMakesChain.callback("I was called back!")
The output when run should look like this:
I was called back! So was I!
Potentially unexpected behavior¶
If a second Deferred were to be chained to the first, the first would be printed twice, although its initial value would only be printed once.
In this case, None
will be the value of deferredMakesChain
at the
time that it is called for the second time, as its initial value has already been
passed to the first chained Deferred’s callback. deferredMakesChain
is still used in both callbacks and is even processed before the values of
the chained deferreds themselves:
from twisted.internet import defer
from twisted.trial import unittest
class ExampleTests(unittest.TestCase):
def testDeferredChaining(self):
# Create two Deferreds
deferredGetsChained = defer.Deferred()
deferredAlsoGetsChained = defer.Deferred()
deferredMakesChain = defer.Deferred()
# Give the chain-ee a callback
deferredGetsChained.addCallback(print, "So was I!")
deferredAlsoGetsChained.addCallback(print, "Me too!")
# Chain the first Deferred to the second
deferredMakesChain.chainDeferred(deferredGetsChained)
deferredMakesChain.chainDeferred(deferredAlsoGetsChained)
# Call the first Deferred back to trigger the callback of the other
deferredMakesChain.callback("I was called back!")
Which results in something like:
Ran 1 test in 0.127s
OK
I was called back! So was I!
None Me too!