主要思路是维护一个列表[(callback1,errback1),(callback2,errback2),…]
每次从最前面取一个callback/errback对,然后依次运行,把运行结果放在current.result结果中传给下一个callback/errback对。如果发生错误就返回一个failure对象,判断之后执行errback
实现嵌套deferred的关键是[chain]列表
chain这个列表用来存放deferred对象
在两层(内外)deferred的情况下外层Deferred和内层Deferred的情况如下:
外层chain:[外层deferred]
内层最终chain:[内层deferred,外层deferred]
外层遇到内层Deferred的时候把自己打包放进内层对象的callback对列表中,用_CONTINUE标识。然后自己暂停运行。
内层被激活后,首先运行内层的回调,运行结束后,就会遇到_CONTINUE标识的外层deferred,把它放进chain。因为chain是一个循环,所以接着执行外层剩下的回调。内层的chain链经过了 [内] -》[内,外]-》[内]-》[]的过程。在内层Deferred的_runCallbacks函数中运行完外层剩余回调函数。
这么写是为了避免递归。
参考:https://blog.youkuaiyun.com/u012592285/article/details/51530810
class Deferred:
called = False # 是一个初始化false为信号量,一旦callback和errback调用之后就置true
paused = False #计数器,当pause大于0(或者为true?)的话callback或者是errback的调用会被暂停。
_debugInfo = None
_suppressAlreadyCalled = False # 是一个很重要的标志,用于deferred的取消机制,当deferred对象没有canceller并且已经被取消了(cancel方法被调用之后),该标志置为True,否则为False。
_runningCallbacks = False #_runningCallbacks是一个标志。当deferred对象的回调链正处于执行状态时为True,这个标志用于阻止_runCallbacks对象的递归调用。
debug = False
_chainedTo = None # 用于嵌套deferred,如果一个deferred对象需要等待另一个deferred对象的值的话,_chainedTo属性将指向 那个deferred对象。
def __init__(self, canceller=None):
self.callbacks = []
self._canceller = canceller
if self.debug:
self._debugInfo = DebugInfo()
self._debugInfo.creator = traceback.format_stack()[:-1]
def addCallbacks(self, callback, errback=None,
callbackArgs=None, callbackKeywords=None,
errbackArgs=None, errbackKeywords=None):
#####主要是通过这个函数添加回调链到self.callbacks这个列表中
def callback(self, result):
assert not isinstance(result, Deferred)
self._startRunCallbacks(result)
def errback(self, fail=None):
if fail is None:
fail = failure.Failure(captureVars=self.debug)
elif not isinstance(fail, failure.Failure):
fail = failure.Failure(fail)
self._startRunCallbacks(fail)
def _runCallbacks(self):
chain = [self]
### 维持一个待处理的deferred栈
while chain:
current = chain[-1]
finished = True
current._chainedTo = None
while current.callbacks:
item = current.callbacks.pop(0)
callback, args, kw = item[
isinstance(current.result, failure.Failure)]
###这里判断了一下回调链中回调函数的执行有没有出错。如果出错了,执行下一步的errback
###如果没有出错,执行下一步的callback
args = args or ()
kw = kw or {}
# Avoid recursion if we can.
if callback is _CONTINUE:
# 实现嵌套deferred的关键步骤
# 这里,内层deferred的回调已经执行完毕
# 接下来要执行被暂停的外层deferred剩下的回调。
# 将里层的运行结果交给外层,将外层deferred标为继续执行并重新添加到deferred链中
# Give the waiting Deferred our current result and then
# forget about that result ourselves.
chainee = args[0] #获得外层Deferred对象
chainee.result = current.result
current.result = None
# Making sure to update _debugInfo
if current._debugInfo is not None:
current._debugInfo.failResult = None
chainee.paused -= 1
chain.append(chainee)
# Delay cleaning this Deferred and popping it from the chain
# until after we've dealt with chainee.
finished = False
break # break之后开始执行外层Deferred的接下来回调
try:
current._runningCallbacks = True
try:
current.result = callback(current.result, *args, **kw)
###执行回调,回调函数的结果保存在result中。
finally:
current._runningCallbacks = False
except:
# Including full frame information in the Failure is quite
# expensive, so we avoid it unless self.debug is set.
current.result = failure.Failure(captureVars=self.debug)
else:
####遇到了嵌套的情况,在这里把它塞到内层Deferred的回调链中
if isinstance(current.result, Deferred):
# The result is another Deferred. If it has a result,
# we can take it and keep going.
resultResult = getattr(current.result, 'result', _NO_RESULT)
if resultResult is _NO_RESULT or isinstance(resultResult, Deferred) or current.result.paused:
# Nope, it didn't. Pause and chain.
current.pause()
current._chainedTo = current.result
# Note: current.result has no result, so it's not
# running its callbacks right now. Therefore we can
# append to the callbacks list directly instead of
# using addCallbacks.
current.result.callbacks.append(current._continuation())
break
else:
# Yep, it did. Steal it.
current.result.result = None
# Make sure _debugInfo's failure state is updated.
if current.result._debugInfo is not None:
current.result._debugInfo.failResult = None
current.result = resultResult
if finished:
if isinstance(current.result, failure.Failure):
current.result.cleanFailure()
if current._debugInfo is None:
current._debugInfo = DebugInfo()
current._debugInfo.failResult = current.result
else:
if current._debugInfo is not None:
current._debugInfo.failResult = None
# This Deferred is done, pop it from the chain and move back up
# to the Deferred which supplied us with our result.
chain.pop()