selenium-webdriver 2.48.2 → 2.53.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (534) hide show
  1. package/CHANGES.md +116 -0
  2. package/NOTICE +1 -1
  3. package/README.md +59 -9
  4. package/builder.js +375 -358
  5. package/chrome.js +549 -586
  6. package/edge.js +378 -0
  7. package/error.js +9 -6
  8. package/example/google_search.js +1 -1
  9. package/example/google_search_generator.js +2 -4
  10. package/example/logging.js +6 -2
  11. package/example/sample.js +21 -0
  12. package/executors.js +11 -27
  13. package/firefox/binary.js +149 -98
  14. package/firefox/extension.js +15 -19
  15. package/firefox/index.js +256 -163
  16. package/firefox/profile.js +223 -243
  17. package/http/index.js +487 -81
  18. package/http/util.js +40 -36
  19. package/ie.js +288 -309
  20. package/index.js +34 -125
  21. package/io/exec.js +58 -39
  22. package/io/index.js +72 -60
  23. package/lib/README +4 -0
  24. package/lib/actions.js +596 -0
  25. package/lib/by.js +277 -0
  26. package/lib/capabilities.js +450 -0
  27. package/lib/{webdriver/command.js → command.js} +91 -72
  28. package/lib/{webdriver/button.js → devmode.js} +13 -8
  29. package/lib/error.js +690 -0
  30. package/lib/events.js +212 -0
  31. package/lib/firefox/amd64/libnoblur64.so +0 -0
  32. package/lib/firefox/i386/libnoblur.so +0 -0
  33. package/lib/firefox/webdriver.json +5 -1
  34. package/lib/firefox/webdriver.xpi +0 -0
  35. package/lib/{webdriver/key.js → input.js} +84 -2
  36. package/lib/logging.js +670 -0
  37. package/lib/{webdriver/promise.js → promise.js} +817 -644
  38. package/lib/safari/client.js +266 -214
  39. package/lib/session.js +80 -0
  40. package/lib/{webdriver/serializable.js → symbols.js} +16 -19
  41. package/lib/test/build.js +4 -4
  42. package/lib/test/data/click_tests/html5_submit_buttons.html +2 -1
  43. package/lib/test/data/click_tests/overlapping_elements.html +15 -4
  44. package/lib/test/data/click_tests/partially_overlapping_elements.html +124 -0
  45. package/lib/test/data/click_tests/wrapped_overlapping_elements.html +13 -0
  46. package/lib/test/data/hidden_partially.html +45 -0
  47. package/lib/test/data/readOnlyPage.html +1 -1
  48. package/lib/test/data/selectPage.html +18 -2
  49. package/lib/test/fileserver.js +3 -4
  50. package/lib/test/index.js +7 -3
  51. package/lib/test/resources.js +1 -1
  52. package/lib/until.js +376 -0
  53. package/lib/webdriver.js +2440 -0
  54. package/net/index.js +4 -0
  55. package/net/portprober.js +16 -12
  56. package/opera.js +295 -314
  57. package/package.json +6 -5
  58. package/phantomjs.js +144 -147
  59. package/proxy.js +10 -6
  60. package/remote/index.js +289 -238
  61. package/safari.js +326 -311
  62. package/test/chrome/options_test.js +11 -9
  63. package/test/element_finding_test.js +51 -13
  64. package/test/execute_script_test.js +17 -3
  65. package/test/firefox/firefox_test.js +0 -32
  66. package/test/http/http_test.js +671 -61
  67. package/test/http/util_test.js +25 -23
  68. package/test/io_test.js +67 -1
  69. package/test/lib/by_test.js +139 -0
  70. package/test/lib/capabilities_test.js +111 -0
  71. package/test/lib/error_test.js +325 -0
  72. package/test/lib/events_test.js +177 -0
  73. package/test/lib/logging_test.js +272 -0
  74. package/test/{promise_aplus_test.js → lib/promise_aplus_test.js} +4 -13
  75. package/test/lib/promise_error_test.js +808 -0
  76. package/test/lib/promise_flow_test.js +2282 -0
  77. package/test/lib/promise_generator_test.js +308 -0
  78. package/test/lib/promise_test.js +996 -0
  79. package/test/lib/testutil.js +90 -0
  80. package/test/lib/until_test.js +400 -0
  81. package/test/lib/webdriver_test.js +2157 -0
  82. package/test/page_loading_test.js +7 -9
  83. package/test/remote_test.js +50 -3
  84. package/test/session_test.js +53 -0
  85. package/test/stale_element_test.js +2 -2
  86. package/test/testing/assert_test.js +374 -0
  87. package/test/testing/index_test.js +9 -11
  88. package/testing/assert.js +334 -17
  89. package/testing/index.js +12 -2
  90. package/_base.js +0 -200
  91. package/docs/Changes.html +0 -356
  92. package/docs/class_bot_Error.html +0 -15
  93. package/docs/class_webdriver_ActionSequence.html +0 -115
  94. package/docs/class_webdriver_Alert.html +0 -24
  95. package/docs/class_webdriver_AlertPromise.html +0 -92
  96. package/docs/class_webdriver_Capabilities.html +0 -60
  97. package/docs/class_webdriver_Command.html +0 -15
  98. package/docs/class_webdriver_EventEmitter.html +0 -35
  99. package/docs/class_webdriver_FileDetector.html +0 -21
  100. package/docs/class_webdriver_Locator.html +0 -12
  101. package/docs/class_webdriver_Serializable.html +0 -9
  102. package/docs/class_webdriver_Session.html +0 -13
  103. package/docs/class_webdriver_TouchSequence.html +0 -49
  104. package/docs/class_webdriver_UnhandledAlertError.html +0 -18
  105. package/docs/class_webdriver_WebDriver.html +0 -313
  106. package/docs/class_webdriver_WebDriver_Logs.html +0 -15
  107. package/docs/class_webdriver_WebDriver_Navigation.html +0 -16
  108. package/docs/class_webdriver_WebDriver_Options.html +0 -41
  109. package/docs/class_webdriver_WebDriver_TargetLocator.html +0 -38
  110. package/docs/class_webdriver_WebDriver_Timeouts.html +0 -29
  111. package/docs/class_webdriver_WebDriver_Window.html +0 -27
  112. package/docs/class_webdriver_WebElement.html +0 -223
  113. package/docs/class_webdriver_WebElementPromise.html +0 -274
  114. package/docs/class_webdriver_http_Executor.html +0 -22
  115. package/docs/class_webdriver_http_Request.html +0 -12
  116. package/docs/class_webdriver_http_Response.html +0 -13
  117. package/docs/class_webdriver_logging_Entry.html +0 -15
  118. package/docs/class_webdriver_logging_Level.html +0 -55
  119. package/docs/class_webdriver_logging_LogRecord.html +0 -45
  120. package/docs/class_webdriver_logging_Logger.html +0 -119
  121. package/docs/class_webdriver_logging_Preferences.html +0 -8
  122. package/docs/class_webdriver_promise_CancellationError.html +0 -17
  123. package/docs/class_webdriver_promise_ControlFlow.html +0 -153
  124. package/docs/class_webdriver_promise_Deferred.html +0 -84
  125. package/docs/class_webdriver_promise_MultipleUnhandledRejectionError.html +0 -14
  126. package/docs/class_webdriver_promise_Promise.html +0 -75
  127. package/docs/class_webdriver_stacktrace_Frame.html +0 -20
  128. package/docs/class_webdriver_stacktrace_Snapshot.html +0 -6
  129. package/docs/class_webdriver_testing_Assertion.html +0 -99
  130. package/docs/class_webdriver_testing_Assertion_DelegatingMatcher_.html +0 -13
  131. package/docs/class_webdriver_testing_ContainsMatcher.html +0 -11
  132. package/docs/class_webdriver_testing_NegatedAssertion.html +0 -97
  133. package/docs/class_webdriver_until_Condition.html +0 -7
  134. package/docs/dossier.css +0 -1
  135. package/docs/dossier.js +0 -86
  136. package/docs/enum_bot_ErrorCode.html +0 -3
  137. package/docs/enum_bot_Error_State.html +0 -2
  138. package/docs/enum_webdriver_Browser.html +0 -2
  139. package/docs/enum_webdriver_Button.html +0 -2
  140. package/docs/enum_webdriver_Capability.html +0 -33
  141. package/docs/enum_webdriver_CommandName.html +0 -3
  142. package/docs/enum_webdriver_Key.html +0 -12
  143. package/docs/enum_webdriver_logging_Type.html +0 -6
  144. package/docs/enum_webdriver_promise_ControlFlow_EventType.html +0 -9
  145. package/docs/index.html +0 -125
  146. package/docs/interface_webdriver_CommandExecutor.html +0 -9
  147. package/docs/interface_webdriver_http_Client.html +0 -10
  148. package/docs/interface_webdriver_promise_Thenable.html +0 -77
  149. package/docs/module_selenium-webdriver.html +0 -23
  150. package/docs/module_selenium-webdriver__base.html +0 -23
  151. package/docs/module_selenium-webdriver__base_class_Context.html +0 -5
  152. package/docs/module_selenium-webdriver_builder.html +0 -2
  153. package/docs/module_selenium-webdriver_builder_class_Builder.html +0 -138
  154. package/docs/module_selenium-webdriver_chrome.html +0 -90
  155. package/docs/module_selenium-webdriver_chrome_class_Driver.html +0 -280
  156. package/docs/module_selenium-webdriver_chrome_class_Options.html +0 -127
  157. package/docs/module_selenium-webdriver_chrome_class_ServiceBuilder.html +0 -46
  158. package/docs/module_selenium-webdriver_class_ActionSequence.html +0 -115
  159. package/docs/module_selenium-webdriver_class_Builder.html +0 -138
  160. package/docs/module_selenium-webdriver_class_Capabilities.html +0 -60
  161. package/docs/module_selenium-webdriver_class_Command.html +0 -15
  162. package/docs/module_selenium-webdriver_class_EventEmitter.html +0 -35
  163. package/docs/module_selenium-webdriver_class_FileDetector.html +0 -21
  164. package/docs/module_selenium-webdriver_class_Serializable.html +0 -9
  165. package/docs/module_selenium-webdriver_class_Session.html +0 -13
  166. package/docs/module_selenium-webdriver_class_WebDriver.html +0 -313
  167. package/docs/module_selenium-webdriver_class_WebElement.html +0 -223
  168. package/docs/module_selenium-webdriver_class_WebElementPromise.html +0 -274
  169. package/docs/module_selenium-webdriver_enum_Browser.html +0 -2
  170. package/docs/module_selenium-webdriver_enum_Button.html +0 -2
  171. package/docs/module_selenium-webdriver_enum_Capability.html +0 -33
  172. package/docs/module_selenium-webdriver_enum_CommandName.html +0 -3
  173. package/docs/module_selenium-webdriver_enum_Key.html +0 -12
  174. package/docs/module_selenium-webdriver_error.html +0 -4
  175. package/docs/module_selenium-webdriver_error_class_Error.html +0 -15
  176. package/docs/module_selenium-webdriver_error_enum_ErrorCode.html +0 -3
  177. package/docs/module_selenium-webdriver_executors.html +0 -10
  178. package/docs/module_selenium-webdriver_executors_class_DeferredExecutor.html +0 -12
  179. package/docs/module_selenium-webdriver_firefox.html +0 -68
  180. package/docs/module_selenium-webdriver_firefox_binary.html +0 -5
  181. package/docs/module_selenium-webdriver_firefox_binary_class_Binary.html +0 -20
  182. package/docs/module_selenium-webdriver_firefox_class_Binary.html +0 -20
  183. package/docs/module_selenium-webdriver_firefox_class_Driver.html +0 -276
  184. package/docs/module_selenium-webdriver_firefox_class_Options.html +0 -19
  185. package/docs/module_selenium-webdriver_firefox_class_Profile.html +0 -50
  186. package/docs/module_selenium-webdriver_firefox_extension.html +0 -8
  187. package/docs/module_selenium-webdriver_firefox_profile.html +0 -13
  188. package/docs/module_selenium-webdriver_firefox_profile_class_Profile.html +0 -50
  189. package/docs/module_selenium-webdriver_http.html +0 -9
  190. package/docs/module_selenium-webdriver_http_class_Executor.html +0 -22
  191. package/docs/module_selenium-webdriver_http_class_HttpClient.html +0 -16
  192. package/docs/module_selenium-webdriver_http_class_Request.html +0 -12
  193. package/docs/module_selenium-webdriver_http_class_Response.html +0 -13
  194. package/docs/module_selenium-webdriver_http_util.html +0 -17
  195. package/docs/module_selenium-webdriver_ie.html +0 -11
  196. package/docs/module_selenium-webdriver_ie_class_Driver.html +0 -274
  197. package/docs/module_selenium-webdriver_ie_class_Options.html +0 -89
  198. package/docs/module_selenium-webdriver_ie_enum_Level.html +0 -1
  199. package/docs/module_selenium-webdriver_io.html +0 -37
  200. package/docs/module_selenium-webdriver_io_exec.html +0 -6
  201. package/docs/module_selenium-webdriver_namespace_By.html +0 -56
  202. package/docs/module_selenium-webdriver_namespace_error.html +0 -4
  203. package/docs/module_selenium-webdriver_namespace_logging.html +0 -18
  204. package/docs/module_selenium-webdriver_namespace_promise.html +0 -163
  205. package/docs/module_selenium-webdriver_namespace_stacktrace.html +0 -17
  206. package/docs/module_selenium-webdriver_namespace_until.html +0 -82
  207. package/docs/module_selenium-webdriver_net.html +0 -7
  208. package/docs/module_selenium-webdriver_net_portprober.html +0 -12
  209. package/docs/module_selenium-webdriver_opera.html +0 -62
  210. package/docs/module_selenium-webdriver_opera_class_Driver.html +0 -276
  211. package/docs/module_selenium-webdriver_opera_class_Options.html +0 -44
  212. package/docs/module_selenium-webdriver_opera_class_ServiceBuilder.html +0 -35
  213. package/docs/module_selenium-webdriver_phantomjs.html +0 -2
  214. package/docs/module_selenium-webdriver_phantomjs_class_Driver.html +0 -299
  215. package/docs/module_selenium-webdriver_proxy.html +0 -28
  216. package/docs/module_selenium-webdriver_remote.html +0 -8
  217. package/docs/module_selenium-webdriver_remote_class_DriverService.html +0 -32
  218. package/docs/module_selenium-webdriver_remote_class_FileDetector.html +0 -22
  219. package/docs/module_selenium-webdriver_remote_class_SeleniumServer.html +0 -41
  220. package/docs/module_selenium-webdriver_safari.html +0 -9
  221. package/docs/module_selenium-webdriver_safari_class_Driver.html +0 -279
  222. package/docs/module_selenium-webdriver_safari_class_Options.html +0 -23
  223. package/docs/module_selenium-webdriver_testing.html +0 -74
  224. package/docs/module_selenium-webdriver_testing_assert.html +0 -9
  225. package/docs/namespace_bot.html +0 -4
  226. package/docs/namespace_bot_json.html +0 -20
  227. package/docs/namespace_bot_response.html +0 -18
  228. package/docs/namespace_bot_userAgent.html +0 -33
  229. package/docs/namespace_webdriver.html +0 -30
  230. package/docs/namespace_webdriver_By.html +0 -56
  231. package/docs/namespace_webdriver_http.html +0 -6
  232. package/docs/namespace_webdriver_logging.html +0 -70
  233. package/docs/namespace_webdriver_promise.html +0 -688
  234. package/docs/namespace_webdriver_stacktrace.html +0 -17
  235. package/docs/namespace_webdriver_testing.html +0 -7
  236. package/docs/namespace_webdriver_testing_assert.html +0 -9
  237. package/docs/namespace_webdriver_testing_asserts.html +0 -18
  238. package/docs/namespace_webdriver_until.html +0 -82
  239. package/docs/source/_base.js.src.html +0 -1
  240. package/docs/source/builder.js.src.html +0 -1
  241. package/docs/source/chrome.js.src.html +0 -1
  242. package/docs/source/error.js.src.html +0 -1
  243. package/docs/source/executors.js.src.html +0 -1
  244. package/docs/source/firefox/binary.js.src.html +0 -1
  245. package/docs/source/firefox/extension.js.src.html +0 -1
  246. package/docs/source/firefox/index.js.src.html +0 -1
  247. package/docs/source/firefox/profile.js.src.html +0 -1
  248. package/docs/source/http/index.js.src.html +0 -1
  249. package/docs/source/http/util.js.src.html +0 -1
  250. package/docs/source/ie.js.src.html +0 -1
  251. package/docs/source/index.js.src.html +0 -1
  252. package/docs/source/io/exec.js.src.html +0 -1
  253. package/docs/source/io/index.js.src.html +0 -1
  254. package/docs/source/lib/atoms/error.js.src.html +0 -1
  255. package/docs/source/lib/atoms/json.js.src.html +0 -1
  256. package/docs/source/lib/atoms/response.js.src.html +0 -1
  257. package/docs/source/lib/atoms/userAgent.js.src.html +0 -1
  258. package/docs/source/lib/goog/array/array.js.src.html +0 -1
  259. package/docs/source/lib/goog/asserts/asserts.js.src.html +0 -1
  260. package/docs/source/lib/goog/async/freelist.js.src.html +0 -1
  261. package/docs/source/lib/goog/async/nexttick.js.src.html +0 -1
  262. package/docs/source/lib/goog/async/run.js.src.html +0 -1
  263. package/docs/source/lib/goog/async/workqueue.js.src.html +0 -1
  264. package/docs/source/lib/goog/base.js.src.html +0 -1
  265. package/docs/source/lib/goog/debug/debug.js.src.html +0 -1
  266. package/docs/source/lib/goog/debug/entrypointregistry.js.src.html +0 -1
  267. package/docs/source/lib/goog/debug/error.js.src.html +0 -1
  268. package/docs/source/lib/goog/debug/logbuffer.js.src.html +0 -1
  269. package/docs/source/lib/goog/debug/logger.js.src.html +0 -1
  270. package/docs/source/lib/goog/debug/logrecord.js.src.html +0 -1
  271. package/docs/source/lib/goog/deps.js.src.html +0 -1
  272. package/docs/source/lib/goog/disposable/disposable.js.src.html +0 -1
  273. package/docs/source/lib/goog/disposable/idisposable.js.src.html +0 -1
  274. package/docs/source/lib/goog/dom/browserfeature.js.src.html +0 -1
  275. package/docs/source/lib/goog/dom/dom.js.src.html +0 -1
  276. package/docs/source/lib/goog/dom/nodetype.js.src.html +0 -1
  277. package/docs/source/lib/goog/dom/safe.js.src.html +0 -1
  278. package/docs/source/lib/goog/dom/tagname.js.src.html +0 -1
  279. package/docs/source/lib/goog/dom/tags.js.src.html +0 -1
  280. package/docs/source/lib/goog/dom/vendor.js.src.html +0 -1
  281. package/docs/source/lib/goog/events/browserevent.js.src.html +0 -1
  282. package/docs/source/lib/goog/events/browserfeature.js.src.html +0 -1
  283. package/docs/source/lib/goog/events/event.js.src.html +0 -1
  284. package/docs/source/lib/goog/events/eventid.js.src.html +0 -1
  285. package/docs/source/lib/goog/events/events.js.src.html +0 -1
  286. package/docs/source/lib/goog/events/eventtarget.js.src.html +0 -1
  287. package/docs/source/lib/goog/events/eventtype.js.src.html +0 -1
  288. package/docs/source/lib/goog/events/keycodes.js.src.html +0 -1
  289. package/docs/source/lib/goog/events/listenable.js.src.html +0 -1
  290. package/docs/source/lib/goog/events/listener.js.src.html +0 -1
  291. package/docs/source/lib/goog/events/listenermap.js.src.html +0 -1
  292. package/docs/source/lib/goog/fs/url.js.src.html +0 -1
  293. package/docs/source/lib/goog/functions/functions.js.src.html +0 -1
  294. package/docs/source/lib/goog/html/safehtml.js.src.html +0 -1
  295. package/docs/source/lib/goog/html/safescript.js.src.html +0 -1
  296. package/docs/source/lib/goog/html/safestyle.js.src.html +0 -1
  297. package/docs/source/lib/goog/html/safestylesheet.js.src.html +0 -1
  298. package/docs/source/lib/goog/html/safeurl.js.src.html +0 -1
  299. package/docs/source/lib/goog/html/trustedresourceurl.js.src.html +0 -1
  300. package/docs/source/lib/goog/html/uncheckedconversions.js.src.html +0 -1
  301. package/docs/source/lib/goog/i18n/bidi.js.src.html +0 -1
  302. package/docs/source/lib/goog/iter/iter.js.src.html +0 -1
  303. package/docs/source/lib/goog/json/json.js.src.html +0 -1
  304. package/docs/source/lib/goog/labs/testing/assertthat.js.src.html +0 -1
  305. package/docs/source/lib/goog/labs/testing/logicmatcher.js.src.html +0 -1
  306. package/docs/source/lib/goog/labs/testing/matcher.js.src.html +0 -1
  307. package/docs/source/lib/goog/labs/testing/numbermatcher.js.src.html +0 -1
  308. package/docs/source/lib/goog/labs/testing/objectmatcher.js.src.html +0 -1
  309. package/docs/source/lib/goog/labs/testing/stringmatcher.js.src.html +0 -1
  310. package/docs/source/lib/goog/labs/useragent/browser.js.src.html +0 -1
  311. package/docs/source/lib/goog/labs/useragent/engine.js.src.html +0 -1
  312. package/docs/source/lib/goog/labs/useragent/platform.js.src.html +0 -1
  313. package/docs/source/lib/goog/labs/useragent/util.js.src.html +0 -1
  314. package/docs/source/lib/goog/log/log.js.src.html +0 -1
  315. package/docs/source/lib/goog/math/box.js.src.html +0 -1
  316. package/docs/source/lib/goog/math/coordinate.js.src.html +0 -1
  317. package/docs/source/lib/goog/math/math.js.src.html +0 -1
  318. package/docs/source/lib/goog/math/rect.js.src.html +0 -1
  319. package/docs/source/lib/goog/math/size.js.src.html +0 -1
  320. package/docs/source/lib/goog/net/wrapperxmlhttpfactory.js.src.html +0 -1
  321. package/docs/source/lib/goog/net/xhrlike.js.src.html +0 -1
  322. package/docs/source/lib/goog/net/xmlhttp.js.src.html +0 -1
  323. package/docs/source/lib/goog/net/xmlhttpfactory.js.src.html +0 -1
  324. package/docs/source/lib/goog/object/object.js.src.html +0 -1
  325. package/docs/source/lib/goog/promise/promise.js.src.html +0 -1
  326. package/docs/source/lib/goog/promise/resolver.js.src.html +0 -1
  327. package/docs/source/lib/goog/promise/thenable.js.src.html +0 -1
  328. package/docs/source/lib/goog/reflect/reflect.js.src.html +0 -1
  329. package/docs/source/lib/goog/string/const.js.src.html +0 -1
  330. package/docs/source/lib/goog/string/string.js.src.html +0 -1
  331. package/docs/source/lib/goog/string/typedstring.js.src.html +0 -1
  332. package/docs/source/lib/goog/structs/collection.js.src.html +0 -1
  333. package/docs/source/lib/goog/structs/map.js.src.html +0 -1
  334. package/docs/source/lib/goog/structs/set.js.src.html +0 -1
  335. package/docs/source/lib/goog/structs/structs.js.src.html +0 -1
  336. package/docs/source/lib/goog/style/style.js.src.html +0 -1
  337. package/docs/source/lib/goog/testing/asserts.js.src.html +0 -1
  338. package/docs/source/lib/goog/testing/events/events.js.src.html +0 -1
  339. package/docs/source/lib/goog/testing/functionmock.js.src.html +0 -1
  340. package/docs/source/lib/goog/testing/jsunit.js.src.html +0 -1
  341. package/docs/source/lib/goog/testing/loosemock.js.src.html +0 -1
  342. package/docs/source/lib/goog/testing/mock.js.src.html +0 -1
  343. package/docs/source/lib/goog/testing/mockclock.js.src.html +0 -1
  344. package/docs/source/lib/goog/testing/mockcontrol.js.src.html +0 -1
  345. package/docs/source/lib/goog/testing/mockinterface.js.src.html +0 -1
  346. package/docs/source/lib/goog/testing/mockmatchers.js.src.html +0 -1
  347. package/docs/source/lib/goog/testing/objectpropertystring.js.src.html +0 -1
  348. package/docs/source/lib/goog/testing/propertyreplacer.js.src.html +0 -1
  349. package/docs/source/lib/goog/testing/recordfunction.js.src.html +0 -1
  350. package/docs/source/lib/goog/testing/stacktrace.js.src.html +0 -1
  351. package/docs/source/lib/goog/testing/strictmock.js.src.html +0 -1
  352. package/docs/source/lib/goog/testing/testcase.js.src.html +0 -1
  353. package/docs/source/lib/goog/testing/testrunner.js.src.html +0 -1
  354. package/docs/source/lib/goog/uri/uri.js.src.html +0 -1
  355. package/docs/source/lib/goog/uri/utils.js.src.html +0 -1
  356. package/docs/source/lib/goog/useragent/product.js.src.html +0 -1
  357. package/docs/source/lib/goog/useragent/product_isversion.js.src.html +0 -1
  358. package/docs/source/lib/goog/useragent/useragent.js.src.html +0 -1
  359. package/docs/source/lib/webdriver/actionsequence.js.src.html +0 -1
  360. package/docs/source/lib/webdriver/button.js.src.html +0 -1
  361. package/docs/source/lib/webdriver/capabilities.js.src.html +0 -1
  362. package/docs/source/lib/webdriver/command.js.src.html +0 -1
  363. package/docs/source/lib/webdriver/events.js.src.html +0 -1
  364. package/docs/source/lib/webdriver/http/http.js.src.html +0 -1
  365. package/docs/source/lib/webdriver/key.js.src.html +0 -1
  366. package/docs/source/lib/webdriver/locators.js.src.html +0 -1
  367. package/docs/source/lib/webdriver/logging.js.src.html +0 -1
  368. package/docs/source/lib/webdriver/promise.js.src.html +0 -1
  369. package/docs/source/lib/webdriver/serializable.js.src.html +0 -1
  370. package/docs/source/lib/webdriver/session.js.src.html +0 -1
  371. package/docs/source/lib/webdriver/stacktrace.js.src.html +0 -1
  372. package/docs/source/lib/webdriver/testing/asserts.js.src.html +0 -1
  373. package/docs/source/lib/webdriver/touchsequence.js.src.html +0 -1
  374. package/docs/source/lib/webdriver/until.js.src.html +0 -1
  375. package/docs/source/lib/webdriver/webdriver.js.src.html +0 -1
  376. package/docs/source/net/index.js.src.html +0 -1
  377. package/docs/source/net/portprober.js.src.html +0 -1
  378. package/docs/source/opera.js.src.html +0 -1
  379. package/docs/source/phantomjs.js.src.html +0 -1
  380. package/docs/source/proxy.js.src.html +0 -1
  381. package/docs/source/remote/index.js.src.html +0 -1
  382. package/docs/source/safari.js.src.html +0 -1
  383. package/docs/source/testing/assert.js.src.html +0 -1
  384. package/docs/source/testing/index.js.src.html +0 -1
  385. package/docs/types.js +0 -1
  386. package/lib/atoms/error.js +0 -202
  387. package/lib/atoms/json.js +0 -80
  388. package/lib/atoms/response.js +0 -110
  389. package/lib/atoms/userAgent.js +0 -257
  390. package/lib/goog/LICENSE +0 -176
  391. package/lib/goog/array/array.js +0 -1654
  392. package/lib/goog/asserts/asserts.js +0 -365
  393. package/lib/goog/async/freelist.js +0 -88
  394. package/lib/goog/async/nexttick.js +0 -241
  395. package/lib/goog/async/run.js +0 -133
  396. package/lib/goog/async/workqueue.js +0 -139
  397. package/lib/goog/base.js +0 -2548
  398. package/lib/goog/debug/debug.js +0 -653
  399. package/lib/goog/debug/entrypointregistry.js +0 -158
  400. package/lib/goog/debug/error.js +0 -63
  401. package/lib/goog/debug/logbuffer.js +0 -148
  402. package/lib/goog/debug/logger.js +0 -873
  403. package/lib/goog/debug/logrecord.js +0 -242
  404. package/lib/goog/deps.js +0 -151
  405. package/lib/goog/disposable/disposable.js +0 -307
  406. package/lib/goog/disposable/idisposable.js +0 -45
  407. package/lib/goog/dom/browserfeature.js +0 -72
  408. package/lib/goog/dom/dom.js +0 -2991
  409. package/lib/goog/dom/nodetype.js +0 -48
  410. package/lib/goog/dom/safe.js +0 -347
  411. package/lib/goog/dom/tagname.js +0 -160
  412. package/lib/goog/dom/tags.js +0 -41
  413. package/lib/goog/dom/vendor.js +0 -96
  414. package/lib/goog/events/browserevent.js +0 -400
  415. package/lib/goog/events/browserfeature.js +0 -85
  416. package/lib/goog/events/event.js +0 -143
  417. package/lib/goog/events/eventid.js +0 -47
  418. package/lib/goog/events/events.js +0 -984
  419. package/lib/goog/events/eventtarget.js +0 -394
  420. package/lib/goog/events/eventtype.js +0 -237
  421. package/lib/goog/events/keycodes.js +0 -427
  422. package/lib/goog/events/listenable.js +0 -335
  423. package/lib/goog/events/listener.js +0 -131
  424. package/lib/goog/events/listenermap.js +0 -308
  425. package/lib/goog/fs/url.js +0 -109
  426. package/lib/goog/functions/functions.js +0 -442
  427. package/lib/goog/html/safehtml.js +0 -757
  428. package/lib/goog/html/safescript.js +0 -234
  429. package/lib/goog/html/safestyle.js +0 -442
  430. package/lib/goog/html/safestylesheet.js +0 -276
  431. package/lib/goog/html/safeurl.js +0 -398
  432. package/lib/goog/html/trustedresourceurl.js +0 -224
  433. package/lib/goog/html/uncheckedconversions.js +0 -232
  434. package/lib/goog/i18n/bidi.js +0 -908
  435. package/lib/goog/iter/iter.js +0 -1302
  436. package/lib/goog/json/json.js +0 -363
  437. package/lib/goog/labs/testing/assertthat.js +0 -58
  438. package/lib/goog/labs/testing/logicmatcher.js +0 -212
  439. package/lib/goog/labs/testing/matcher.js +0 -80
  440. package/lib/goog/labs/testing/numbermatcher.js +0 -346
  441. package/lib/goog/labs/testing/objectmatcher.js +0 -317
  442. package/lib/goog/labs/testing/stringmatcher.js +0 -415
  443. package/lib/goog/labs/useragent/browser.js +0 -341
  444. package/lib/goog/labs/useragent/engine.js +0 -160
  445. package/lib/goog/labs/useragent/platform.js +0 -160
  446. package/lib/goog/labs/useragent/util.js +0 -148
  447. package/lib/goog/log/log.js +0 -197
  448. package/lib/goog/math/box.js +0 -398
  449. package/lib/goog/math/coordinate.js +0 -268
  450. package/lib/goog/math/math.js +0 -451
  451. package/lib/goog/math/rect.js +0 -476
  452. package/lib/goog/math/size.js +0 -227
  453. package/lib/goog/net/wrapperxmlhttpfactory.js +0 -71
  454. package/lib/goog/net/xhrlike.js +0 -124
  455. package/lib/goog/net/xmlhttp.js +0 -246
  456. package/lib/goog/net/xmlhttpfactory.js +0 -67
  457. package/lib/goog/object/object.js +0 -686
  458. package/lib/goog/promise/promise.js +0 -1350
  459. package/lib/goog/promise/resolver.js +0 -48
  460. package/lib/goog/promise/thenable.js +0 -126
  461. package/lib/goog/reflect/reflect.js +0 -77
  462. package/lib/goog/string/const.js +0 -182
  463. package/lib/goog/string/string.js +0 -1599
  464. package/lib/goog/string/typedstring.js +0 -48
  465. package/lib/goog/structs/collection.js +0 -56
  466. package/lib/goog/structs/map.js +0 -457
  467. package/lib/goog/structs/set.js +0 -279
  468. package/lib/goog/structs/structs.js +0 -354
  469. package/lib/goog/style/style.js +0 -2037
  470. package/lib/goog/testing/asserts.js +0 -1278
  471. package/lib/goog/testing/events/events.js +0 -767
  472. package/lib/goog/testing/functionmock.js +0 -175
  473. package/lib/goog/testing/jsunit.js +0 -162
  474. package/lib/goog/testing/loosemock.js +0 -242
  475. package/lib/goog/testing/mock.js +0 -645
  476. package/lib/goog/testing/mockclock.js +0 -606
  477. package/lib/goog/testing/mockcontrol.js +0 -220
  478. package/lib/goog/testing/mockinterface.js +0 -45
  479. package/lib/goog/testing/mockmatchers.js +0 -400
  480. package/lib/goog/testing/objectpropertystring.js +0 -68
  481. package/lib/goog/testing/propertyreplacer.js +0 -262
  482. package/lib/goog/testing/recordfunction.js +0 -215
  483. package/lib/goog/testing/stacktrace.js +0 -594
  484. package/lib/goog/testing/strictmock.js +0 -130
  485. package/lib/goog/testing/testcase.js +0 -1629
  486. package/lib/goog/testing/testrunner.js +0 -440
  487. package/lib/goog/uri/uri.js +0 -1524
  488. package/lib/goog/uri/utils.js +0 -1064
  489. package/lib/goog/useragent/product.js +0 -183
  490. package/lib/goog/useragent/product_isversion.js +0 -144
  491. package/lib/goog/useragent/useragent.js +0 -572
  492. package/lib/webdriver/actionsequence.js +0 -356
  493. package/lib/webdriver/builder.js +0 -207
  494. package/lib/webdriver/capabilities.js +0 -412
  495. package/lib/webdriver/events.js +0 -179
  496. package/lib/webdriver/firefoxdomexecutor.js +0 -175
  497. package/lib/webdriver/http/corsclient.js +0 -133
  498. package/lib/webdriver/http/http.js +0 -525
  499. package/lib/webdriver/http/xhrclient.js +0 -67
  500. package/lib/webdriver/locators.js +0 -257
  501. package/lib/webdriver/logging.js +0 -347
  502. package/lib/webdriver/session.js +0 -74
  503. package/lib/webdriver/stacktrace.js +0 -619
  504. package/lib/webdriver/test/builder_test.js +0 -53
  505. package/lib/webdriver/test/capabilities_test.js +0 -72
  506. package/lib/webdriver/test/events_test.js +0 -203
  507. package/lib/webdriver/test/http/corsclient_test.js +0 -151
  508. package/lib/webdriver/test/http/http_test.js +0 -428
  509. package/lib/webdriver/test/http/xhrclient_test.js +0 -196
  510. package/lib/webdriver/test/locators_test.js +0 -59
  511. package/lib/webdriver/test/logging_test.js +0 -85
  512. package/lib/webdriver/test/promise_error_test.js +0 -892
  513. package/lib/webdriver/test/promise_flow_test.js +0 -2365
  514. package/lib/webdriver/test/promise_generator_test.js +0 -323
  515. package/lib/webdriver/test/promise_test.js +0 -2012
  516. package/lib/webdriver/test/stacktrace_test.js +0 -480
  517. package/lib/webdriver/test/test_bootstrap.js +0 -67
  518. package/lib/webdriver/test/testing/asserts_test.js +0 -117
  519. package/lib/webdriver/test/testing/client_test.js +0 -88
  520. package/lib/webdriver/test/testing/testcase_test.js +0 -229
  521. package/lib/webdriver/test/testutil.js +0 -209
  522. package/lib/webdriver/test/testutil_test.js +0 -104
  523. package/lib/webdriver/test/until_test.js +0 -411
  524. package/lib/webdriver/test/webdriver_generator_test.js +0 -92
  525. package/lib/webdriver/test/webdriver_test.js +0 -2369
  526. package/lib/webdriver/testing/asserts.js +0 -487
  527. package/lib/webdriver/testing/client.js +0 -179
  528. package/lib/webdriver/testing/jsunit.js +0 -363
  529. package/lib/webdriver/testing/testcase.js +0 -168
  530. package/lib/webdriver/testing/window.js +0 -244
  531. package/lib/webdriver/touchsequence.js +0 -248
  532. package/lib/webdriver/until.js +0 -412
  533. package/lib/webdriver/webdriver.js +0 -2511
  534. package/test/_base_test.js +0 -129
@@ -1 +0,0 @@
1
- <!DOCTYPE html><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"><meta http-equiv="Content-Language" content="en"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>promise.js</title><link href="../../../dossier.css" rel="stylesheet" type="text/css"><header><div><form><div><input type="search" placeholder="Search" tabindex="1"></div></form></div></header><main><article class="srcfile"><h1>lib/webdriver/promise.js</h1><div><table><tr><td><a id="l1"></a><a href="#l1">1</a><td>// Licensed to the Software Freedom Conservancy (SFC) under one<tr><td><a id="l2"></a><a href="#l2">2</a><td>// or more contributor license agreements. See the NOTICE file<tr><td><a id="l3"></a><a href="#l3">3</a><td>// distributed with this work for additional information<tr><td><a id="l4"></a><a href="#l4">4</a><td>// regarding copyright ownership. The SFC licenses this file<tr><td><a id="l5"></a><a href="#l5">5</a><td>// to you under the Apache License, Version 2.0 (the<tr><td><a id="l6"></a><a href="#l6">6</a><td>// &quot;License&quot;); you may not use this file except in compliance<tr><td><a id="l7"></a><a href="#l7">7</a><td>// with the License. You may obtain a copy of the License at<tr><td><a id="l8"></a><a href="#l8">8</a><td>//<tr><td><a id="l9"></a><a href="#l9">9</a><td>// http://www.apache.org/licenses/LICENSE-2.0<tr><td><a id="l10"></a><a href="#l10">10</a><td>//<tr><td><a id="l11"></a><a href="#l11">11</a><td>// Unless required by applicable law or agreed to in writing,<tr><td><a id="l12"></a><a href="#l12">12</a><td>// software distributed under the License is distributed on an<tr><td><a id="l13"></a><a href="#l13">13</a><td>// &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY<tr><td><a id="l14"></a><a href="#l14">14</a><td>// KIND, either express or implied. See the License for the<tr><td><a id="l15"></a><a href="#l15">15</a><td>// specific language governing permissions and limitations<tr><td><a id="l16"></a><a href="#l16">16</a><td>// under the License.<tr><td><a id="l17"></a><a href="#l17">17</a><td><tr><td><a id="l18"></a><a href="#l18">18</a><td>/**<tr><td><a id="l19"></a><a href="#l19">19</a><td> * @license Portions of this code are from the Dojo toolkit, received under the<tr><td><a id="l20"></a><a href="#l20">20</a><td> * BSD License:<tr><td><a id="l21"></a><a href="#l21">21</a><td> * Redistribution and use in source and binary forms, with or without<tr><td><a id="l22"></a><a href="#l22">22</a><td> * modification, are permitted provided that the following conditions are met:<tr><td><a id="l23"></a><a href="#l23">23</a><td> *<tr><td><a id="l24"></a><a href="#l24">24</a><td> * * Redistributions of source code must retain the above copyright notice,<tr><td><a id="l25"></a><a href="#l25">25</a><td> * this list of conditions and the following disclaimer.<tr><td><a id="l26"></a><a href="#l26">26</a><td> * * Redistributions in binary form must reproduce the above copyright notice,<tr><td><a id="l27"></a><a href="#l27">27</a><td> * this list of conditions and the following disclaimer in the documentation<tr><td><a id="l28"></a><a href="#l28">28</a><td> * and/or other materials provided with the distribution.<tr><td><a id="l29"></a><a href="#l29">29</a><td> * * Neither the name of the Dojo Foundation nor the names of its contributors<tr><td><a id="l30"></a><a href="#l30">30</a><td> * may be used to endorse or promote products derived from this software<tr><td><a id="l31"></a><a href="#l31">31</a><td> * without specific prior written permission.<tr><td><a id="l32"></a><a href="#l32">32</a><td> *<tr><td><a id="l33"></a><a href="#l33">33</a><td> * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;<tr><td><a id="l34"></a><a href="#l34">34</a><td> * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<tr><td><a id="l35"></a><a href="#l35">35</a><td> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<tr><td><a id="l36"></a><a href="#l36">36</a><td> * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<tr><td><a id="l37"></a><a href="#l37">37</a><td> * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<tr><td><a id="l38"></a><a href="#l38">38</a><td> * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<tr><td><a id="l39"></a><a href="#l39">39</a><td> * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<tr><td><a id="l40"></a><a href="#l40">40</a><td> * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<tr><td><a id="l41"></a><a href="#l41">41</a><td> * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<tr><td><a id="l42"></a><a href="#l42">42</a><td> * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<tr><td><a id="l43"></a><a href="#l43">43</a><td> * POSSIBILITY OF SUCH DAMAGE.<tr><td><a id="l44"></a><a href="#l44">44</a><td> */<tr><td><a id="l45"></a><a href="#l45">45</a><td><tr><td><a id="l46"></a><a href="#l46">46</a><td>/**<tr><td><a id="l47"></a><a href="#l47">47</a><td> * @fileoverview<tr><td><a id="l48"></a><a href="#l48">48</a><td> * The promise module is centered around the<tr><td><a id="l49"></a><a href="#l49">49</a><td> * {@linkplain webdriver.promise.ControlFlow ControlFlow}, a class that<tr><td><a id="l50"></a><a href="#l50">50</a><td> * coordinates the execution of asynchronous tasks. The ControlFlow allows users<tr><td><a id="l51"></a><a href="#l51">51</a><td> * to focus on the imperative commands for their script without worrying about<tr><td><a id="l52"></a><a href="#l52">52</a><td> * chaining together every single asynchronous action, which can be tedious and<tr><td><a id="l53"></a><a href="#l53">53</a><td> * verbose. APIs may be layered on top of the control flow to read as if they<tr><td><a id="l54"></a><a href="#l54">54</a><td> * were synchronous. For instance, the core<tr><td><a id="l55"></a><a href="#l55">55</a><td> * {@linkplain webdriver.WebDriver WebDriver} API is built on top of the<tr><td><a id="l56"></a><a href="#l56">56</a><td> * control flow, allowing users to write<tr><td><a id="l57"></a><a href="#l57">57</a><td> *<tr><td><a id="l58"></a><a href="#l58">58</a><td> * driver.get(&#39;http://www.google.com/ncr&#39;);<tr><td><a id="l59"></a><a href="#l59">59</a><td> * driver.findElement({name: &#39;q&#39;}).sendKeys(&#39;webdriver&#39;);<tr><td><a id="l60"></a><a href="#l60">60</a><td> * driver.findElement({name: &#39;btnGn&#39;}).click();<tr><td><a id="l61"></a><a href="#l61">61</a><td> *<tr><td><a id="l62"></a><a href="#l62">62</a><td> * instead of<tr><td><a id="l63"></a><a href="#l63">63</a><td> *<tr><td><a id="l64"></a><a href="#l64">64</a><td> * driver.get(&#39;http://www.google.com/ncr&#39;)<tr><td><a id="l65"></a><a href="#l65">65</a><td> * .then(function() {<tr><td><a id="l66"></a><a href="#l66">66</a><td> * return driver.findElement({name: &#39;q&#39;});<tr><td><a id="l67"></a><a href="#l67">67</a><td> * })<tr><td><a id="l68"></a><a href="#l68">68</a><td> * .then(function(q) {<tr><td><a id="l69"></a><a href="#l69">69</a><td> * return q.sendKeys(&#39;webdriver&#39;);<tr><td><a id="l70"></a><a href="#l70">70</a><td> * })<tr><td><a id="l71"></a><a href="#l71">71</a><td> * .then(function() {<tr><td><a id="l72"></a><a href="#l72">72</a><td> * return driver.findElement({name: &#39;btnG&#39;});<tr><td><a id="l73"></a><a href="#l73">73</a><td> * })<tr><td><a id="l74"></a><a href="#l74">74</a><td> * .then(function(btnG) {<tr><td><a id="l75"></a><a href="#l75">75</a><td> * return btnG.click();<tr><td><a id="l76"></a><a href="#l76">76</a><td> * });<tr><td><a id="l77"></a><a href="#l77">77</a><td> *<tr><td><a id="l78"></a><a href="#l78">78</a><td> * ## Tasks and Task Queues<tr><td><a id="l79"></a><a href="#l79">79</a><td> *<tr><td><a id="l80"></a><a href="#l80">80</a><td> * The control flow is based on the concept of tasks and task queues. Tasks are<tr><td><a id="l81"></a><a href="#l81">81</a><td> * functions that define the basic unit of work for the control flow to execute.<tr><td><a id="l82"></a><a href="#l82">82</a><td> * Each task is scheduled via<tr><td><a id="l83"></a><a href="#l83">83</a><td> * {@link webdriver.promise.ControlFlow#execute() ControlFlow#execute()}, which<tr><td><a id="l84"></a><a href="#l84">84</a><td> * will return a {@link webdriver.promise.Promise Promise} that will be resolved<tr><td><a id="l85"></a><a href="#l85">85</a><td> * with the task&#39;s result.<tr><td><a id="l86"></a><a href="#l86">86</a><td> *<tr><td><a id="l87"></a><a href="#l87">87</a><td> * A task queue contains all of the tasks scheduled within a single turn of the<tr><td><a id="l88"></a><a href="#l88">88</a><td> * [JavaScript event loop][JSEL]. The control flow will create a new task queue<tr><td><a id="l89"></a><a href="#l89">89</a><td> * the first time a task is scheduled within an event loop.<tr><td><a id="l90"></a><a href="#l90">90</a><td> *<tr><td><a id="l91"></a><a href="#l91">91</a><td> * var flow = promise.controlFlow();<tr><td><a id="l92"></a><a href="#l92">92</a><td> * flow.execute(foo); // Creates a new task queue and inserts foo.<tr><td><a id="l93"></a><a href="#l93">93</a><td> * flow.execute(bar); // Inserts bar into the same queue as foo.<tr><td><a id="l94"></a><a href="#l94">94</a><td> * setTimeout(function() {<tr><td><a id="l95"></a><a href="#l95">95</a><td> * flow.execute(baz); // Creates a new task queue and inserts baz.<tr><td><a id="l96"></a><a href="#l96">96</a><td> * }, 0);<tr><td><a id="l97"></a><a href="#l97">97</a><td> *<tr><td><a id="l98"></a><a href="#l98">98</a><td> * Whenever the control flow creates a new task queue, it will automatically<tr><td><a id="l99"></a><a href="#l99">99</a><td> * begin executing tasks in the next available turn of the event loop. This<tr><td><a id="l100"></a><a href="#l100">100</a><td> * execution is scheduled using a &quot;micro-task&quot; timer, such as a (native)<tr><td><a id="l101"></a><a href="#l101">101</a><td> * `Promise.then()` callback.<tr><td><a id="l102"></a><a href="#l102">102</a><td> *<tr><td><a id="l103"></a><a href="#l103">103</a><td> * setTimeout(() =&gt; console.log(&#39;a&#39;));<tr><td><a id="l104"></a><a href="#l104">104</a><td> * Promise.resolve().then(() =&gt; console.log(&#39;b&#39;)); // A native promise.<tr><td><a id="l105"></a><a href="#l105">105</a><td> * flow.execute(() =&gt; console.log(&#39;c&#39;));<tr><td><a id="l106"></a><a href="#l106">106</a><td> * Promise.resolve().then(() =&gt; console.log(&#39;d&#39;));<tr><td><a id="l107"></a><a href="#l107">107</a><td> * setTimeout(() =&gt; console.log(&#39;fin&#39;));<tr><td><a id="l108"></a><a href="#l108">108</a><td> * // b<tr><td><a id="l109"></a><a href="#l109">109</a><td> * // c<tr><td><a id="l110"></a><a href="#l110">110</a><td> * // d<tr><td><a id="l111"></a><a href="#l111">111</a><td> * // a<tr><td><a id="l112"></a><a href="#l112">112</a><td> * // fin<tr><td><a id="l113"></a><a href="#l113">113</a><td> *<tr><td><a id="l114"></a><a href="#l114">114</a><td> * In the example above, b/c/d is logged before a/fin because native promises<tr><td><a id="l115"></a><a href="#l115">115</a><td> * and this module use &quot;micro-task&quot; timers, which have a higher priority than<tr><td><a id="l116"></a><a href="#l116">116</a><td> * &quot;macro-tasks&quot; like `setTimeout`.<tr><td><a id="l117"></a><a href="#l117">117</a><td> *<tr><td><a id="l118"></a><a href="#l118">118</a><td> * ## Task Execution<tr><td><a id="l119"></a><a href="#l119">119</a><td> *<tr><td><a id="l120"></a><a href="#l120">120</a><td> * Upon creating a task queue, and whenever an exisiting queue completes a task,<tr><td><a id="l121"></a><a href="#l121">121</a><td> * the control flow will schedule a micro-task timer to process any scheduled<tr><td><a id="l122"></a><a href="#l122">122</a><td> * tasks. This ensures no task is ever started within the same turn of the<tr><td><a id="l123"></a><a href="#l123">123</a><td> * JavaScript event loop in which it was scheduled, nor is a task ever started<tr><td><a id="l124"></a><a href="#l124">124</a><td> * within the same turn that another finishes.<tr><td><a id="l125"></a><a href="#l125">125</a><td> *<tr><td><a id="l126"></a><a href="#l126">126</a><td> * When the execution timer fires, a single task will be dequeued and executed.<tr><td><a id="l127"></a><a href="#l127">127</a><td> * There are several important events that may occur while executing a task<tr><td><a id="l128"></a><a href="#l128">128</a><td> * function:<tr><td><a id="l129"></a><a href="#l129">129</a><td> *<tr><td><a id="l130"></a><a href="#l130">130</a><td> * 1. A new task queue is created by a call to<tr><td><a id="l131"></a><a href="#l131">131</a><td> * {@link webdriver.promise.ControlFlow#execute ControlFlow#execute()}. Any<tr><td><a id="l132"></a><a href="#l132">132</a><td> * tasks scheduled within this task queue are considered subtasks of the<tr><td><a id="l133"></a><a href="#l133">133</a><td> * current task.<tr><td><a id="l134"></a><a href="#l134">134</a><td> * 2. The task function throws an error. Any scheduled tasks are immediately<tr><td><a id="l135"></a><a href="#l135">135</a><td> * discarded and the task&#39;s promised result (previously returned by<tr><td><a id="l136"></a><a href="#l136">136</a><td> * {@link webdriver.promise.ControlFlow#execute ControlFlow#execute()}) is<tr><td><a id="l137"></a><a href="#l137">137</a><td> * immediately rejected with the thrown error.<tr><td><a id="l138"></a><a href="#l138">138</a><td> * 3. The task function returns sucessfully.<tr><td><a id="l139"></a><a href="#l139">139</a><td> *<tr><td><a id="l140"></a><a href="#l140">140</a><td> * If a task function created a new task queue, the control flow will wait for<tr><td><a id="l141"></a><a href="#l141">141</a><td> * that queue to complete before processing the task result. If the queue<tr><td><a id="l142"></a><a href="#l142">142</a><td> * completes without error, the flow will settle the task&#39;s promise with the<tr><td><a id="l143"></a><a href="#l143">143</a><td> * value originaly returned by the task function. On the other hand, if the task<tr><td><a id="l144"></a><a href="#l144">144</a><td> * queue termintes with an error, the task&#39;s promise will be rejected with that<tr><td><a id="l145"></a><a href="#l145">145</a><td> * error.<tr><td><a id="l146"></a><a href="#l146">146</a><td> *<tr><td><a id="l147"></a><a href="#l147">147</a><td> * flow.execute(function() {<tr><td><a id="l148"></a><a href="#l148">148</a><td> * flow.execute(() =&gt; console.log(&#39;a&#39;));<tr><td><a id="l149"></a><a href="#l149">149</a><td> * flow.execute(() =&gt; console.log(&#39;b&#39;));<tr><td><a id="l150"></a><a href="#l150">150</a><td> * });<tr><td><a id="l151"></a><a href="#l151">151</a><td> * flow.execute(() =&gt; console.log(&#39;c&#39;));<tr><td><a id="l152"></a><a href="#l152">152</a><td> * // a<tr><td><a id="l153"></a><a href="#l153">153</a><td> * // b<tr><td><a id="l154"></a><a href="#l154">154</a><td> * // c<tr><td><a id="l155"></a><a href="#l155">155</a><td> *<tr><td><a id="l156"></a><a href="#l156">156</a><td> * ## Promise Integration<tr><td><a id="l157"></a><a href="#l157">157</a><td> *<tr><td><a id="l158"></a><a href="#l158">158</a><td> * In addition to the {@link webdriver.promise.ControlFlow ControlFlow} class,<tr><td><a id="l159"></a><a href="#l159">159</a><td> * the promise module also exports a [Promise/A+]<tr><td><a id="l160"></a><a href="#l160">160</a><td> * {@linkplain webdriver.promise.Promise implementation} that is deeply<tr><td><a id="l161"></a><a href="#l161">161</a><td> * integrated with the ControlFlow. First and foremost, each promise<tr><td><a id="l162"></a><a href="#l162">162</a><td> * {@linkplain webdriver.promise.Promise#then() callback} is scheduled with the<tr><td><a id="l163"></a><a href="#l163">163</a><td> * control flow as a task. As a result, each callback is invoked in its own turn<tr><td><a id="l164"></a><a href="#l164">164</a><td> * of the JavaScript event loop with its own task queue. If any tasks are<tr><td><a id="l165"></a><a href="#l165">165</a><td> * scheduled within a callback, the callback&#39;s promised result will not be<tr><td><a id="l166"></a><a href="#l166">166</a><td> * settled until the task queue has completed.<tr><td><a id="l167"></a><a href="#l167">167</a><td> *<tr><td><a id="l168"></a><a href="#l168">168</a><td> * promise.fulfilled().then(function() {<tr><td><a id="l169"></a><a href="#l169">169</a><td> * flow.execute(function() {<tr><td><a id="l170"></a><a href="#l170">170</a><td> * console.log(&#39;b&#39;);<tr><td><a id="l171"></a><a href="#l171">171</a><td> * });<tr><td><a id="l172"></a><a href="#l172">172</a><td> * }).then(() =&gt; console.log(&#39;a&#39;));<tr><td><a id="l173"></a><a href="#l173">173</a><td> * // b<tr><td><a id="l174"></a><a href="#l174">174</a><td> * // a<tr><td><a id="l175"></a><a href="#l175">175</a><td> *<tr><td><a id="l176"></a><a href="#l176">176</a><td> * ### Scheduling Promise Callbacks &lt;a id=&quot;scheduling_callbacks&quot;&gt;&lt;/a&gt;<tr><td><a id="l177"></a><a href="#l177">177</a><td> *<tr><td><a id="l178"></a><a href="#l178">178</a><td> * How callbacks are scheduled in the control flow depends on when they are<tr><td><a id="l179"></a><a href="#l179">179</a><td> * attached to the promise. Callbacks attached to a _previously_ resolved<tr><td><a id="l180"></a><a href="#l180">180</a><td> * promise are immediately enqueued as subtasks of the currently running task.<tr><td><a id="l181"></a><a href="#l181">181</a><td> *<tr><td><a id="l182"></a><a href="#l182">182</a><td> * var p = promise.fulfilled();<tr><td><a id="l183"></a><a href="#l183">183</a><td> * flow.execute(function() {<tr><td><a id="l184"></a><a href="#l184">184</a><td> * flow.execute(() =&gt; console.log(&#39;A&#39;));<tr><td><a id="l185"></a><a href="#l185">185</a><td> * p.then( () =&gt; console.log(&#39;B&#39;));<tr><td><a id="l186"></a><a href="#l186">186</a><td> * flow.execute(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l187"></a><a href="#l187">187</a><td> * p.then( () =&gt; console.log(&#39;D&#39;));<tr><td><a id="l188"></a><a href="#l188">188</a><td> * }).then(function() {<tr><td><a id="l189"></a><a href="#l189">189</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l190"></a><a href="#l190">190</a><td> * });<tr><td><a id="l191"></a><a href="#l191">191</a><td> * // A<tr><td><a id="l192"></a><a href="#l192">192</a><td> * // B<tr><td><a id="l193"></a><a href="#l193">193</a><td> * // C<tr><td><a id="l194"></a><a href="#l194">194</a><td> * // D<tr><td><a id="l195"></a><a href="#l195">195</a><td> * // fin<tr><td><a id="l196"></a><a href="#l196">196</a><td> *<tr><td><a id="l197"></a><a href="#l197">197</a><td> * When a promise is resolved while a task function is on the call stack, any<tr><td><a id="l198"></a><a href="#l198">198</a><td> * callbacks also registered in that stack frame are scheduled as if the promise<tr><td><a id="l199"></a><a href="#l199">199</a><td> * were already resolved:<tr><td><a id="l200"></a><a href="#l200">200</a><td> *<tr><td><a id="l201"></a><a href="#l201">201</a><td> * var d = promise.defer();<tr><td><a id="l202"></a><a href="#l202">202</a><td> * flow.execute(function() {<tr><td><a id="l203"></a><a href="#l203">203</a><td> * flow.execute( () =&gt; console.log(&#39;A&#39;));<tr><td><a id="l204"></a><a href="#l204">204</a><td> * d.promise.then(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l205"></a><a href="#l205">205</a><td> * flow.execute( () =&gt; console.log(&#39;C&#39;));<tr><td><a id="l206"></a><a href="#l206">206</a><td> * d.promise.then(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l207"></a><a href="#l207">207</a><td> *<tr><td><a id="l208"></a><a href="#l208">208</a><td> * d.fulfill();<tr><td><a id="l209"></a><a href="#l209">209</a><td> * }).then(function() {<tr><td><a id="l210"></a><a href="#l210">210</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l211"></a><a href="#l211">211</a><td> * });<tr><td><a id="l212"></a><a href="#l212">212</a><td> * // A<tr><td><a id="l213"></a><a href="#l213">213</a><td> * // B<tr><td><a id="l214"></a><a href="#l214">214</a><td> * // C<tr><td><a id="l215"></a><a href="#l215">215</a><td> * // D<tr><td><a id="l216"></a><a href="#l216">216</a><td> * // fin<tr><td><a id="l217"></a><a href="#l217">217</a><td> *<tr><td><a id="l218"></a><a href="#l218">218</a><td> * Callbacks attached to an _unresolved_ promise within a task function are<tr><td><a id="l219"></a><a href="#l219">219</a><td> * only weakly scheduled as subtasks and will be dropped if they reach the<tr><td><a id="l220"></a><a href="#l220">220</a><td> * front of the queue before the promise is resolved. In the example below, the<tr><td><a id="l221"></a><a href="#l221">221</a><td> * callbacks for `B` &amp; `D` are dropped as sub-tasks since they are attached to<tr><td><a id="l222"></a><a href="#l222">222</a><td> * an unresolved promise when they reach the front of the task queue.<tr><td><a id="l223"></a><a href="#l223">223</a><td> *<tr><td><a id="l224"></a><a href="#l224">224</a><td> * var d = promise.defer();<tr><td><a id="l225"></a><a href="#l225">225</a><td> * flow.execute(function() {<tr><td><a id="l226"></a><a href="#l226">226</a><td> * flow.execute( () =&gt; console.log(&#39;A&#39;));<tr><td><a id="l227"></a><a href="#l227">227</a><td> * d.promise.then(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l228"></a><a href="#l228">228</a><td> * flow.execute( () =&gt; console.log(&#39;C&#39;));<tr><td><a id="l229"></a><a href="#l229">229</a><td> * d.promise.then(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l230"></a><a href="#l230">230</a><td> *<tr><td><a id="l231"></a><a href="#l231">231</a><td> * setTimeout(d.fulfill, 20);<tr><td><a id="l232"></a><a href="#l232">232</a><td> * }).then(function() {<tr><td><a id="l233"></a><a href="#l233">233</a><td> * console.log(&#39;fin&#39;)<tr><td><a id="l234"></a><a href="#l234">234</a><td> * });<tr><td><a id="l235"></a><a href="#l235">235</a><td> * // A<tr><td><a id="l236"></a><a href="#l236">236</a><td> * // C<tr><td><a id="l237"></a><a href="#l237">237</a><td> * // fin<tr><td><a id="l238"></a><a href="#l238">238</a><td> * // B<tr><td><a id="l239"></a><a href="#l239">239</a><td> * // D<tr><td><a id="l240"></a><a href="#l240">240</a><td> *<tr><td><a id="l241"></a><a href="#l241">241</a><td> * If a promise is resolved while a task function is on the call stack, any<tr><td><a id="l242"></a><a href="#l242">242</a><td> * previously registered and unqueued callbacks (i.e. either attached while no<tr><td><a id="l243"></a><a href="#l243">243</a><td> * task was on the call stack, or previously dropped as described above) act as<tr><td><a id="l244"></a><a href="#l244">244</a><td> * _interrupts_ and are inserted at the front of the task queue. If multiple<tr><td><a id="l245"></a><a href="#l245">245</a><td> * promises are fulfilled, their interrupts are enqueued in the order the<tr><td><a id="l246"></a><a href="#l246">246</a><td> * promises are resolved.<tr><td><a id="l247"></a><a href="#l247">247</a><td> *<tr><td><a id="l248"></a><a href="#l248">248</a><td> * var d1 = promise.defer();<tr><td><a id="l249"></a><a href="#l249">249</a><td> * d1.promise.then(() =&gt; console.log(&#39;A&#39;));<tr><td><a id="l250"></a><a href="#l250">250</a><td> *<tr><td><a id="l251"></a><a href="#l251">251</a><td> * var d2 = promise.defer();<tr><td><a id="l252"></a><a href="#l252">252</a><td> * d2.promise.then(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l253"></a><a href="#l253">253</a><td> *<tr><td><a id="l254"></a><a href="#l254">254</a><td> * flow.execute(function() {<tr><td><a id="l255"></a><a href="#l255">255</a><td> * d1.promise.then(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l256"></a><a href="#l256">256</a><td> * flow.execute(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l257"></a><a href="#l257">257</a><td> * });<tr><td><a id="l258"></a><a href="#l258">258</a><td> * flow.execute(function() {<tr><td><a id="l259"></a><a href="#l259">259</a><td> * flow.execute(() =&gt; console.log(&#39;E&#39;));<tr><td><a id="l260"></a><a href="#l260">260</a><td> * flow.execute(() =&gt; console.log(&#39;F&#39;));<tr><td><a id="l261"></a><a href="#l261">261</a><td> * d1.fulfill();<tr><td><a id="l262"></a><a href="#l262">262</a><td> * d2.fulfill();<tr><td><a id="l263"></a><a href="#l263">263</a><td> * }).then(function() {<tr><td><a id="l264"></a><a href="#l264">264</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l265"></a><a href="#l265">265</a><td> * });<tr><td><a id="l266"></a><a href="#l266">266</a><td> * // D<tr><td><a id="l267"></a><a href="#l267">267</a><td> * // A<tr><td><a id="l268"></a><a href="#l268">268</a><td> * // C<tr><td><a id="l269"></a><a href="#l269">269</a><td> * // B<tr><td><a id="l270"></a><a href="#l270">270</a><td> * // E<tr><td><a id="l271"></a><a href="#l271">271</a><td> * // F<tr><td><a id="l272"></a><a href="#l272">272</a><td> * // fin<tr><td><a id="l273"></a><a href="#l273">273</a><td> *<tr><td><a id="l274"></a><a href="#l274">274</a><td> * Within a task function (or callback), each step of a promise chain acts as<tr><td><a id="l275"></a><a href="#l275">275</a><td> * an interrupt on the task queue:<tr><td><a id="l276"></a><a href="#l276">276</a><td> *<tr><td><a id="l277"></a><a href="#l277">277</a><td> * var d = promise.defer();<tr><td><a id="l278"></a><a href="#l278">278</a><td> * flow.execute(function() {<tr><td><a id="l279"></a><a href="#l279">279</a><td> * d.promise.<tr><td><a id="l280"></a><a href="#l280">280</a><td> * then(() =&gt; console.log(&#39;A&#39;)).<tr><td><a id="l281"></a><a href="#l281">281</a><td> * then(() =&gt; console.log(&#39;B&#39;)).<tr><td><a id="l282"></a><a href="#l282">282</a><td> * then(() =&gt; console.log(&#39;C&#39;)).<tr><td><a id="l283"></a><a href="#l283">283</a><td> * then(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l284"></a><a href="#l284">284</a><td> *<tr><td><a id="l285"></a><a href="#l285">285</a><td> * flow.execute(() =&gt; console.log(&#39;E&#39;));<tr><td><a id="l286"></a><a href="#l286">286</a><td> * d.fulfill();<tr><td><a id="l287"></a><a href="#l287">287</a><td> * }).then(function() {<tr><td><a id="l288"></a><a href="#l288">288</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l289"></a><a href="#l289">289</a><td> * });<tr><td><a id="l290"></a><a href="#l290">290</a><td> * // A<tr><td><a id="l291"></a><a href="#l291">291</a><td> * // B<tr><td><a id="l292"></a><a href="#l292">292</a><td> * // C<tr><td><a id="l293"></a><a href="#l293">293</a><td> * // D<tr><td><a id="l294"></a><a href="#l294">294</a><td> * // E<tr><td><a id="l295"></a><a href="#l295">295</a><td> * // fin<tr><td><a id="l296"></a><a href="#l296">296</a><td> *<tr><td><a id="l297"></a><a href="#l297">297</a><td> * If there are multiple promise chains derived from a single promise, they are<tr><td><a id="l298"></a><a href="#l298">298</a><td> * processed in the order created:<tr><td><a id="l299"></a><a href="#l299">299</a><td> *<tr><td><a id="l300"></a><a href="#l300">300</a><td> * var d = promise.defer();<tr><td><a id="l301"></a><a href="#l301">301</a><td> * flow.execute(function() {<tr><td><a id="l302"></a><a href="#l302">302</a><td> * var chain = d.promise.then(() =&gt; console.log(&#39;A&#39;));<tr><td><a id="l303"></a><a href="#l303">303</a><td> *<tr><td><a id="l304"></a><a href="#l304">304</a><td> * chain.then(() =&gt; console.log(&#39;B&#39;)).<tr><td><a id="l305"></a><a href="#l305">305</a><td> * then(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l306"></a><a href="#l306">306</a><td> *<tr><td><a id="l307"></a><a href="#l307">307</a><td> * chain.then(() =&gt; console.log(&#39;D&#39;)).<tr><td><a id="l308"></a><a href="#l308">308</a><td> * then(() =&gt; console.log(&#39;E&#39;));<tr><td><a id="l309"></a><a href="#l309">309</a><td> *<tr><td><a id="l310"></a><a href="#l310">310</a><td> * flow.execute(() =&gt; console.log(&#39;F&#39;));<tr><td><a id="l311"></a><a href="#l311">311</a><td> *<tr><td><a id="l312"></a><a href="#l312">312</a><td> * d.fulfill();<tr><td><a id="l313"></a><a href="#l313">313</a><td> * }).then(function() {<tr><td><a id="l314"></a><a href="#l314">314</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l315"></a><a href="#l315">315</a><td> * });<tr><td><a id="l316"></a><a href="#l316">316</a><td> * // A<tr><td><a id="l317"></a><a href="#l317">317</a><td> * // B<tr><td><a id="l318"></a><a href="#l318">318</a><td> * // C<tr><td><a id="l319"></a><a href="#l319">319</a><td> * // D<tr><td><a id="l320"></a><a href="#l320">320</a><td> * // E<tr><td><a id="l321"></a><a href="#l321">321</a><td> * // F<tr><td><a id="l322"></a><a href="#l322">322</a><td> * // fin<tr><td><a id="l323"></a><a href="#l323">323</a><td> *<tr><td><a id="l324"></a><a href="#l324">324</a><td> * Even though a subtask&#39;s promised result will never resolve while the task<tr><td><a id="l325"></a><a href="#l325">325</a><td> * function is on the stack, it will be treated as a promise resolved within the<tr><td><a id="l326"></a><a href="#l326">326</a><td> * task. In all other scenarios, a task&#39;s promise behaves just like a normal<tr><td><a id="l327"></a><a href="#l327">327</a><td> * promise. In the sample below, `C/D` is loggged before `B` because the<tr><td><a id="l328"></a><a href="#l328">328</a><td> * resolution of `subtask1` interrupts the flow of the enclosing task. Within<tr><td><a id="l329"></a><a href="#l329">329</a><td> * the final subtask, `E/F` is logged in order because `subtask1` is a resolved<tr><td><a id="l330"></a><a href="#l330">330</a><td> * promise when that task runs.<tr><td><a id="l331"></a><a href="#l331">331</a><td> *<tr><td><a id="l332"></a><a href="#l332">332</a><td> * flow.execute(function() {<tr><td><a id="l333"></a><a href="#l333">333</a><td> * var subtask1 = flow.execute(() =&gt; console.log(&#39;A&#39;));<tr><td><a id="l334"></a><a href="#l334">334</a><td> * var subtask2 = flow.execute(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l335"></a><a href="#l335">335</a><td> *<tr><td><a id="l336"></a><a href="#l336">336</a><td> * subtask1.then(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l337"></a><a href="#l337">337</a><td> * subtask1.then(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l338"></a><a href="#l338">338</a><td> *<tr><td><a id="l339"></a><a href="#l339">339</a><td> * flow.execute(function() {<tr><td><a id="l340"></a><a href="#l340">340</a><td> * flow.execute(() =&gt; console.log(&#39;E&#39;));<tr><td><a id="l341"></a><a href="#l341">341</a><td> * subtask1.then(() =&gt; console.log(&#39;F&#39;));<tr><td><a id="l342"></a><a href="#l342">342</a><td> * });<tr><td><a id="l343"></a><a href="#l343">343</a><td> * }).then(function() {<tr><td><a id="l344"></a><a href="#l344">344</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l345"></a><a href="#l345">345</a><td> * });<tr><td><a id="l346"></a><a href="#l346">346</a><td> * // A<tr><td><a id="l347"></a><a href="#l347">347</a><td> * // C<tr><td><a id="l348"></a><a href="#l348">348</a><td> * // D<tr><td><a id="l349"></a><a href="#l349">349</a><td> * // B<tr><td><a id="l350"></a><a href="#l350">350</a><td> * // E<tr><td><a id="l351"></a><a href="#l351">351</a><td> * // F<tr><td><a id="l352"></a><a href="#l352">352</a><td> * // fin<tr><td><a id="l353"></a><a href="#l353">353</a><td> *<tr><td><a id="l354"></a><a href="#l354">354</a><td> * Finally, consider the following:<tr><td><a id="l355"></a><a href="#l355">355</a><td> *<tr><td><a id="l356"></a><a href="#l356">356</a><td> * var d = promise.defer();<tr><td><a id="l357"></a><a href="#l357">357</a><td> * d.promise.then(() =&gt; console.log(&#39;A&#39;));<tr><td><a id="l358"></a><a href="#l358">358</a><td> * d.promise.then(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l359"></a><a href="#l359">359</a><td> *<tr><td><a id="l360"></a><a href="#l360">360</a><td> * flow.execute(function() {<tr><td><a id="l361"></a><a href="#l361">361</a><td> * flow.execute( () =&gt; console.log(&#39;C&#39;));<tr><td><a id="l362"></a><a href="#l362">362</a><td> * d.promise.then(() =&gt; console.log(&#39;D&#39;));<tr><td><a id="l363"></a><a href="#l363">363</a><td> *<tr><td><a id="l364"></a><a href="#l364">364</a><td> * flow.execute( () =&gt; console.log(&#39;E&#39;));<tr><td><a id="l365"></a><a href="#l365">365</a><td> * d.promise.then(() =&gt; console.log(&#39;F&#39;));<tr><td><a id="l366"></a><a href="#l366">366</a><td> *<tr><td><a id="l367"></a><a href="#l367">367</a><td> * d.fulfill();<tr><td><a id="l368"></a><a href="#l368">368</a><td> *<tr><td><a id="l369"></a><a href="#l369">369</a><td> * flow.execute( () =&gt; console.log(&#39;G&#39;));<tr><td><a id="l370"></a><a href="#l370">370</a><td> * d.promise.then(() =&gt; console.log(&#39;H&#39;));<tr><td><a id="l371"></a><a href="#l371">371</a><td> * }).then(function() {<tr><td><a id="l372"></a><a href="#l372">372</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l373"></a><a href="#l373">373</a><td> * });<tr><td><a id="l374"></a><a href="#l374">374</a><td> * // A<tr><td><a id="l375"></a><a href="#l375">375</a><td> * // B<tr><td><a id="l376"></a><a href="#l376">376</a><td> * // C<tr><td><a id="l377"></a><a href="#l377">377</a><td> * // D<tr><td><a id="l378"></a><a href="#l378">378</a><td> * // E<tr><td><a id="l379"></a><a href="#l379">379</a><td> * // F<tr><td><a id="l380"></a><a href="#l380">380</a><td> * // G<tr><td><a id="l381"></a><a href="#l381">381</a><td> * // H<tr><td><a id="l382"></a><a href="#l382">382</a><td> * // fin<tr><td><a id="l383"></a><a href="#l383">383</a><td> *<tr><td><a id="l384"></a><a href="#l384">384</a><td> * In this example, callbacks are registered on `d.promise` both before and<tr><td><a id="l385"></a><a href="#l385">385</a><td> * during the invocation of the task function. When `d.fulfill()` is called,<tr><td><a id="l386"></a><a href="#l386">386</a><td> * the callbacks registered before the task (`A` &amp; `B`) are registered as<tr><td><a id="l387"></a><a href="#l387">387</a><td> * interrupts. The remaining callbacks were all attached within the task and<tr><td><a id="l388"></a><a href="#l388">388</a><td> * are scheduled in the flow as standard tasks.<tr><td><a id="l389"></a><a href="#l389">389</a><td> *<tr><td><a id="l390"></a><a href="#l390">390</a><td> * ## Generator Support<tr><td><a id="l391"></a><a href="#l391">391</a><td> *<tr><td><a id="l392"></a><a href="#l392">392</a><td> * [Generators][GF] may be scheduled as tasks within a control flow or attached<tr><td><a id="l393"></a><a href="#l393">393</a><td> * as callbacks to a promise. Each time the generator yields a promise, the<tr><td><a id="l394"></a><a href="#l394">394</a><td> * control flow will wait for that promise to settle before executing the next<tr><td><a id="l395"></a><a href="#l395">395</a><td> * iteration of the generator. The yielded promise&#39;s fulfilled value will be<tr><td><a id="l396"></a><a href="#l396">396</a><td> * passed back into the generator:<tr><td><a id="l397"></a><a href="#l397">397</a><td> *<tr><td><a id="l398"></a><a href="#l398">398</a><td> * flow.execute(function* () {<tr><td><a id="l399"></a><a href="#l399">399</a><td> * var d = promise.defer();<tr><td><a id="l400"></a><a href="#l400">400</a><td> *<tr><td><a id="l401"></a><a href="#l401">401</a><td> * setTimeout(() =&gt; console.log(&#39;...waiting...&#39;), 25);<tr><td><a id="l402"></a><a href="#l402">402</a><td> * setTimeout(() =&gt; d.fulfill(123), 50);<tr><td><a id="l403"></a><a href="#l403">403</a><td> *<tr><td><a id="l404"></a><a href="#l404">404</a><td> * console.log(&#39;start: &#39; + Date.now());<tr><td><a id="l405"></a><a href="#l405">405</a><td> *<tr><td><a id="l406"></a><a href="#l406">406</a><td> * var value = yield d.promise;<tr><td><a id="l407"></a><a href="#l407">407</a><td> * console.log(&#39;mid: %d; value = %d&#39;, Date.now(), value);<tr><td><a id="l408"></a><a href="#l408">408</a><td> *<tr><td><a id="l409"></a><a href="#l409">409</a><td> * yield promise.delayed(10);<tr><td><a id="l410"></a><a href="#l410">410</a><td> * console.log(&#39;end: &#39; + Date.now());<tr><td><a id="l411"></a><a href="#l411">411</a><td> * }).then(function() {<tr><td><a id="l412"></a><a href="#l412">412</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l413"></a><a href="#l413">413</a><td> * });<tr><td><a id="l414"></a><a href="#l414">414</a><td> * // start: 0<tr><td><a id="l415"></a><a href="#l415">415</a><td> * // ...waiting...<tr><td><a id="l416"></a><a href="#l416">416</a><td> * // mid: 50; value = 123<tr><td><a id="l417"></a><a href="#l417">417</a><td> * // end: 60<tr><td><a id="l418"></a><a href="#l418">418</a><td> * // fin<tr><td><a id="l419"></a><a href="#l419">419</a><td> *<tr><td><a id="l420"></a><a href="#l420">420</a><td> * Yielding the result of a promise chain will wait for the entire chain to<tr><td><a id="l421"></a><a href="#l421">421</a><td> * complete:<tr><td><a id="l422"></a><a href="#l422">422</a><td> *<tr><td><a id="l423"></a><a href="#l423">423</a><td> * promise.fulfilled().then(function* () {<tr><td><a id="l424"></a><a href="#l424">424</a><td> * console.log(&#39;start: &#39; + Date.now());<tr><td><a id="l425"></a><a href="#l425">425</a><td> *<tr><td><a id="l426"></a><a href="#l426">426</a><td> * var value = yield flow.<tr><td><a id="l427"></a><a href="#l427">427</a><td> * execute(() =&gt; console.log(&#39;A&#39;)).<tr><td><a id="l428"></a><a href="#l428">428</a><td> * then( () =&gt; console.log(&#39;B&#39;)).<tr><td><a id="l429"></a><a href="#l429">429</a><td> * then( () =&gt; 123);<tr><td><a id="l430"></a><a href="#l430">430</a><td> *<tr><td><a id="l431"></a><a href="#l431">431</a><td> * console.log(&#39;mid: %s; value = %d&#39;, Date.now(), value);<tr><td><a id="l432"></a><a href="#l432">432</a><td> *<tr><td><a id="l433"></a><a href="#l433">433</a><td> * yield flow.execute(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l434"></a><a href="#l434">434</a><td> * }).then(function() {<tr><td><a id="l435"></a><a href="#l435">435</a><td> * console.log(&#39;fin&#39;);<tr><td><a id="l436"></a><a href="#l436">436</a><td> * });<tr><td><a id="l437"></a><a href="#l437">437</a><td> * // start: 0<tr><td><a id="l438"></a><a href="#l438">438</a><td> * // A<tr><td><a id="l439"></a><a href="#l439">439</a><td> * // B<tr><td><a id="l440"></a><a href="#l440">440</a><td> * // mid: 2; value = 123<tr><td><a id="l441"></a><a href="#l441">441</a><td> * // C<tr><td><a id="l442"></a><a href="#l442">442</a><td> * // fin<tr><td><a id="l443"></a><a href="#l443">443</a><td> *<tr><td><a id="l444"></a><a href="#l444">444</a><td> * Yielding a _rejected_ promise will cause the rejected value to be thrown<tr><td><a id="l445"></a><a href="#l445">445</a><td> * within the generator function:<tr><td><a id="l446"></a><a href="#l446">446</a><td> *<tr><td><a id="l447"></a><a href="#l447">447</a><td> * flow.execute(function* () {<tr><td><a id="l448"></a><a href="#l448">448</a><td> * console.log(&#39;start: &#39; + Date.now());<tr><td><a id="l449"></a><a href="#l449">449</a><td> * try {<tr><td><a id="l450"></a><a href="#l450">450</a><td> * yield promise.delayed(10).then(function() {<tr><td><a id="l451"></a><a href="#l451">451</a><td> * throw Error(&#39;boom&#39;);<tr><td><a id="l452"></a><a href="#l452">452</a><td> * });<tr><td><a id="l453"></a><a href="#l453">453</a><td> * } catch (ex) {<tr><td><a id="l454"></a><a href="#l454">454</a><td> * console.log(&#39;caught time: &#39; + Date.now());<tr><td><a id="l455"></a><a href="#l455">455</a><td> * console.log(ex.message);<tr><td><a id="l456"></a><a href="#l456">456</a><td> * }<tr><td><a id="l457"></a><a href="#l457">457</a><td> * });<tr><td><a id="l458"></a><a href="#l458">458</a><td> * // start: 0<tr><td><a id="l459"></a><a href="#l459">459</a><td> * // caught time: 10<tr><td><a id="l460"></a><a href="#l460">460</a><td> * // boom<tr><td><a id="l461"></a><a href="#l461">461</a><td> *<tr><td><a id="l462"></a><a href="#l462">462</a><td> * # Error Handling<tr><td><a id="l463"></a><a href="#l463">463</a><td> *<tr><td><a id="l464"></a><a href="#l464">464</a><td> * ES6 promises do not require users to handle a promise rejections. This can<tr><td><a id="l465"></a><a href="#l465">465</a><td> * result in subtle bugs as the rejections are silently &quot;swallowed&quot; by the<tr><td><a id="l466"></a><a href="#l466">466</a><td> * Promise class.<tr><td><a id="l467"></a><a href="#l467">467</a><td> *<tr><td><a id="l468"></a><a href="#l468">468</a><td> * Promise.reject(Error(&#39;boom&#39;));<tr><td><a id="l469"></a><a href="#l469">469</a><td> * // ... *crickets* ...<tr><td><a id="l470"></a><a href="#l470">470</a><td> *<tr><td><a id="l471"></a><a href="#l471">471</a><td> * Selenium&#39;s {@link webdriver.promise promise} module, on the other hand,<tr><td><a id="l472"></a><a href="#l472">472</a><td> * requires that every rejection be explicitly handled. When a<tr><td><a id="l473"></a><a href="#l473">473</a><td> * {@linkplain webdriver.promise.Promise Promise} is rejected and no callbacks<tr><td><a id="l474"></a><a href="#l474">474</a><td> * are defined on that promise, it is considered an _unhandled rejection_ and<tr><td><a id="l475"></a><a href="#l475">475</a><td> * reproted to the active task queue. If the rejection remains unhandled after<tr><td><a id="l476"></a><a href="#l476">476</a><td> * a single turn of the [event loop][JSEL] (scheduled with a micro-task), it<tr><td><a id="l477"></a><a href="#l477">477</a><td> * will propagate up the stack.<tr><td><a id="l478"></a><a href="#l478">478</a><td> *<tr><td><a id="l479"></a><a href="#l479">479</a><td> * ## Error Propagation<tr><td><a id="l480"></a><a href="#l480">480</a><td> *<tr><td><a id="l481"></a><a href="#l481">481</a><td> * If an unhandled rejection occurs within a task function, that task&#39;s promised<tr><td><a id="l482"></a><a href="#l482">482</a><td> * result is rejected and all remaining subtasks are discarded:<tr><td><a id="l483"></a><a href="#l483">483</a><td> *<tr><td><a id="l484"></a><a href="#l484">484</a><td> * flow.execute(function() {<tr><td><a id="l485"></a><a href="#l485">485</a><td> * // No callbacks registered on promise -&gt; unhandled rejection<tr><td><a id="l486"></a><a href="#l486">486</a><td> * promise.rejected(Error(&#39;boom&#39;));<tr><td><a id="l487"></a><a href="#l487">487</a><td> * flow.execute(function() { console.log(&#39;this will never run&#39;); });<tr><td><a id="l488"></a><a href="#l488">488</a><td> * }).thenCatch(function(e) {<tr><td><a id="l489"></a><a href="#l489">489</a><td> * console.log(e.message);<tr><td><a id="l490"></a><a href="#l490">490</a><td> * });<tr><td><a id="l491"></a><a href="#l491">491</a><td> * // boom<tr><td><a id="l492"></a><a href="#l492">492</a><td> *<tr><td><a id="l493"></a><a href="#l493">493</a><td> * The promised results for discarded tasks are silently rejected with a<tr><td><a id="l494"></a><a href="#l494">494</a><td> * cancellation error and existing callback chains will never fire.<tr><td><a id="l495"></a><a href="#l495">495</a><td> *<tr><td><a id="l496"></a><a href="#l496">496</a><td> * flow.execute(function() {<tr><td><a id="l497"></a><a href="#l497">497</a><td> * promise.rejected(Error(&#39;boom&#39;));<tr><td><a id="l498"></a><a href="#l498">498</a><td> * flow.execute(function() { console.log(&#39;a&#39;); }).<tr><td><a id="l499"></a><a href="#l499">499</a><td> * then(function() { console.log(&#39;b&#39;); });<tr><td><a id="l500"></a><a href="#l500">500</a><td> * }).thenCatch(function(e) {<tr><td><a id="l501"></a><a href="#l501">501</a><td> * console.log(e.message);<tr><td><a id="l502"></a><a href="#l502">502</a><td> * });<tr><td><a id="l503"></a><a href="#l503">503</a><td> * // boom<tr><td><a id="l504"></a><a href="#l504">504</a><td> *<tr><td><a id="l505"></a><a href="#l505">505</a><td> * An unhandled rejection takes precedence over a task function&#39;s returned<tr><td><a id="l506"></a><a href="#l506">506</a><td> * result, even if that value is another promise:<tr><td><a id="l507"></a><a href="#l507">507</a><td> *<tr><td><a id="l508"></a><a href="#l508">508</a><td> * flow.execute(function() {<tr><td><a id="l509"></a><a href="#l509">509</a><td> * promise.rejected(Error(&#39;boom&#39;));<tr><td><a id="l510"></a><a href="#l510">510</a><td> * return flow.execute(someOtherTask);<tr><td><a id="l511"></a><a href="#l511">511</a><td> * }).thenCatch(function(e) {<tr><td><a id="l512"></a><a href="#l512">512</a><td> * console.log(e.message);<tr><td><a id="l513"></a><a href="#l513">513</a><td> * });<tr><td><a id="l514"></a><a href="#l514">514</a><td> * // boom<tr><td><a id="l515"></a><a href="#l515">515</a><td> *<tr><td><a id="l516"></a><a href="#l516">516</a><td> * If there are multiple unhandled rejections within a task, they are packaged<tr><td><a id="l517"></a><a href="#l517">517</a><td> * in a {@link webdriver.promise.MultipleUnhandledRejectionError<tr><td><a id="l518"></a><a href="#l518">518</a><td> * MultipleUnhandledRejectionError}, which has an `errors` property that is a<tr><td><a id="l519"></a><a href="#l519">519</a><td> * `Set` of the recorded unhandled rejections:<tr><td><a id="l520"></a><a href="#l520">520</a><td> *<tr><td><a id="l521"></a><a href="#l521">521</a><td> * flow.execute(function() {<tr><td><a id="l522"></a><a href="#l522">522</a><td> * promise.rejected(Error(&#39;boom1&#39;));<tr><td><a id="l523"></a><a href="#l523">523</a><td> * promise.rejected(Error(&#39;boom2&#39;));<tr><td><a id="l524"></a><a href="#l524">524</a><td> * }).thenCatch(function(ex) {<tr><td><a id="l525"></a><a href="#l525">525</a><td> * console.log(ex instanceof promise.MultipleUnhandledRejectionError);<tr><td><a id="l526"></a><a href="#l526">526</a><td> * for (var e of ex.errors) {<tr><td><a id="l527"></a><a href="#l527">527</a><td> * console.log(e.message);<tr><td><a id="l528"></a><a href="#l528">528</a><td> * }<tr><td><a id="l529"></a><a href="#l529">529</a><td> * });<tr><td><a id="l530"></a><a href="#l530">530</a><td> * // boom1<tr><td><a id="l531"></a><a href="#l531">531</a><td> * // boom2<tr><td><a id="l532"></a><a href="#l532">532</a><td> *<tr><td><a id="l533"></a><a href="#l533">533</a><td> * When a subtask is discarded due to an unreported rejection in its parent<tr><td><a id="l534"></a><a href="#l534">534</a><td> * frame, the existing callbacks on that task will never settle and the<tr><td><a id="l535"></a><a href="#l535">535</a><td> * callbacks will not be invoked. If a new callback is attached ot the subtask<tr><td><a id="l536"></a><a href="#l536">536</a><td> * _after_ it has been discarded, it is handled the same as adding a callback<tr><td><a id="l537"></a><a href="#l537">537</a><td> * to a cancelled promise: the error-callback path is invoked. This behavior is<tr><td><a id="l538"></a><a href="#l538">538</a><td> * intended to handle cases where the user saves a reference to a task promise,<tr><td><a id="l539"></a><a href="#l539">539</a><td> * as illustrated below.<tr><td><a id="l540"></a><a href="#l540">540</a><td> *<tr><td><a id="l541"></a><a href="#l541">541</a><td> * var subTask;<tr><td><a id="l542"></a><a href="#l542">542</a><td> * flow.execute(function() {<tr><td><a id="l543"></a><a href="#l543">543</a><td> * promise.rejected(Error(&#39;boom&#39;));<tr><td><a id="l544"></a><a href="#l544">544</a><td> * subTask = flow.execute(function() {});<tr><td><a id="l545"></a><a href="#l545">545</a><td> * }).thenCatch(function(e) {<tr><td><a id="l546"></a><a href="#l546">546</a><td> * console.log(e.message);<tr><td><a id="l547"></a><a href="#l547">547</a><td> * }).then(function() {<tr><td><a id="l548"></a><a href="#l548">548</a><td> * return subTask.then(<tr><td><a id="l549"></a><a href="#l549">549</a><td> * () =&gt; console.log(&#39;subtask success!&#39;),<tr><td><a id="l550"></a><a href="#l550">550</a><td> * (e) =&gt; console.log(&#39;subtask failed:\n&#39; + e));<tr><td><a id="l551"></a><a href="#l551">551</a><td> * });<tr><td><a id="l552"></a><a href="#l552">552</a><td> * // boom<tr><td><a id="l553"></a><a href="#l553">553</a><td> * // subtask failed:<tr><td><a id="l554"></a><a href="#l554">554</a><td> * // DiscardedTaskError: Task was discarded due to a previous failure: boom<tr><td><a id="l555"></a><a href="#l555">555</a><td> *<tr><td><a id="l556"></a><a href="#l556">556</a><td> * When a subtask fails, its promised result is treated the same as any other<tr><td><a id="l557"></a><a href="#l557">557</a><td> * promise: it must be handled within one turn of the rejection or the unhandled<tr><td><a id="l558"></a><a href="#l558">558</a><td> * rejection is propagated to the parent task. This means users can catch errors<tr><td><a id="l559"></a><a href="#l559">559</a><td> * from complex flows from the top level task:<tr><td><a id="l560"></a><a href="#l560">560</a><td> *<tr><td><a id="l561"></a><a href="#l561">561</a><td> * flow.execute(function() {<tr><td><a id="l562"></a><a href="#l562">562</a><td> * flow.execute(function() {<tr><td><a id="l563"></a><a href="#l563">563</a><td> * flow.execute(function() {<tr><td><a id="l564"></a><a href="#l564">564</a><td> * throw Error(&#39;fail!&#39;);<tr><td><a id="l565"></a><a href="#l565">565</a><td> * });<tr><td><a id="l566"></a><a href="#l566">566</a><td> * });<tr><td><a id="l567"></a><a href="#l567">567</a><td> * }).thenCatch(function(e) {<tr><td><a id="l568"></a><a href="#l568">568</a><td> * console.log(e.message);<tr><td><a id="l569"></a><a href="#l569">569</a><td> * });<tr><td><a id="l570"></a><a href="#l570">570</a><td> * // fail!<tr><td><a id="l571"></a><a href="#l571">571</a><td> *<tr><td><a id="l572"></a><a href="#l572">572</a><td> * ## Unhandled Rejection Events<tr><td><a id="l573"></a><a href="#l573">573</a><td> *<tr><td><a id="l574"></a><a href="#l574">574</a><td> * When an unhandled rejection propagates to the root of the control flow, the<tr><td><a id="l575"></a><a href="#l575">575</a><td> * flow will emit an __uncaughtException__ event. If no listeners are registered<tr><td><a id="l576"></a><a href="#l576">576</a><td> * on the flow, the error will be rethrown to the global error handler: an<tr><td><a id="l577"></a><a href="#l577">577</a><td> * __uncaughtException__ event from the<tr><td><a id="l578"></a><a href="#l578">578</a><td> * [`process`](https://nodejs.org/api/process.html) object in node, or<tr><td><a id="l579"></a><a href="#l579">579</a><td> * `window.onerror` when running in a browser.<tr><td><a id="l580"></a><a href="#l580">580</a><td> *<tr><td><a id="l581"></a><a href="#l581">581</a><td> * Bottom line: you __*must*__ handle rejected promises.<tr><td><a id="l582"></a><a href="#l582">582</a><td> *<tr><td><a id="l583"></a><a href="#l583">583</a><td> * # Promise/A+ Compatibility<tr><td><a id="l584"></a><a href="#l584">584</a><td> *<tr><td><a id="l585"></a><a href="#l585">585</a><td> * This `promise` module is compliant with the [Promise/A+][] specification<tr><td><a id="l586"></a><a href="#l586">586</a><td> * except for sections `2.2.6.1` and `2.2.6.2`:<tr><td><a id="l587"></a><a href="#l587">587</a><td> *<tr><td><a id="l588"></a><a href="#l588">588</a><td> * &gt;<tr><td><a id="l589"></a><a href="#l589">589</a><td> * &gt; - `then` may be called multiple times on the same promise.<tr><td><a id="l590"></a><a href="#l590">590</a><td> * &gt; - If/when `promise` is fulfilled, all respective `onFulfilled` callbacks<tr><td><a id="l591"></a><a href="#l591">591</a><td> * &gt; must execute in the order of their originating calls to `then`.<tr><td><a id="l592"></a><a href="#l592">592</a><td> * &gt; - If/when `promise` is rejected, all respective `onRejected` callbacks<tr><td><a id="l593"></a><a href="#l593">593</a><td> * &gt; must execute in the order of their originating calls to `then`.<tr><td><a id="l594"></a><a href="#l594">594</a><td> * &gt;<tr><td><a id="l595"></a><a href="#l595">595</a><td> *<tr><td><a id="l596"></a><a href="#l596">596</a><td> * Specifically, the conformance tests contains the following scenario (for<tr><td><a id="l597"></a><a href="#l597">597</a><td> * brevity, only the fulfillment version is shown):<tr><td><a id="l598"></a><a href="#l598">598</a><td> *<tr><td><a id="l599"></a><a href="#l599">599</a><td> * var p1 = Promise.resolve();<tr><td><a id="l600"></a><a href="#l600">600</a><td> * p1.then(function() {<tr><td><a id="l601"></a><a href="#l601">601</a><td> * console.log(&#39;A&#39;);<tr><td><a id="l602"></a><a href="#l602">602</a><td> * p1.then(() =&gt; console.log(&#39;B&#39;));<tr><td><a id="l603"></a><a href="#l603">603</a><td> * });<tr><td><a id="l604"></a><a href="#l604">604</a><td> * p1.then(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l605"></a><a href="#l605">605</a><td> * // A<tr><td><a id="l606"></a><a href="#l606">606</a><td> * // C<tr><td><a id="l607"></a><a href="#l607">607</a><td> * // B<tr><td><a id="l608"></a><a href="#l608">608</a><td> *<tr><td><a id="l609"></a><a href="#l609">609</a><td> * Since the [ControlFlow](#scheduling_callbacks) executes promise callbacks as<tr><td><a id="l610"></a><a href="#l610">610</a><td> * tasks, with this module, the result would be<tr><td><a id="l611"></a><a href="#l611">611</a><td> *<tr><td><a id="l612"></a><a href="#l612">612</a><td> * var p2 = promise.fulfilled();<tr><td><a id="l613"></a><a href="#l613">613</a><td> * p2.then(function() {<tr><td><a id="l614"></a><a href="#l614">614</a><td> * console.log(&#39;A&#39;);<tr><td><a id="l615"></a><a href="#l615">615</a><td> * p2.then(() =&gt; console.log(&#39;B&#39;);<tr><td><a id="l616"></a><a href="#l616">616</a><td> * });<tr><td><a id="l617"></a><a href="#l617">617</a><td> * p2.then(() =&gt; console.log(&#39;C&#39;));<tr><td><a id="l618"></a><a href="#l618">618</a><td> * // A<tr><td><a id="l619"></a><a href="#l619">619</a><td> * // B<tr><td><a id="l620"></a><a href="#l620">620</a><td> * // C<tr><td><a id="l621"></a><a href="#l621">621</a><td> *<tr><td><a id="l622"></a><a href="#l622">622</a><td> * [JSEL]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop<tr><td><a id="l623"></a><a href="#l623">623</a><td> * [GF]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*<tr><td><a id="l624"></a><a href="#l624">624</a><td> * [Promise/A+]: https://promisesaplus.com/<tr><td><a id="l625"></a><a href="#l625">625</a><td> */<tr><td><a id="l626"></a><a href="#l626">626</a><td><tr><td><a id="l627"></a><a href="#l627">627</a><td>goog.module(&#39;webdriver.promise&#39;);<tr><td><a id="l628"></a><a href="#l628">628</a><td>goog.module.declareLegacyNamespace();<tr><td><a id="l629"></a><a href="#l629">629</a><td><tr><td><a id="l630"></a><a href="#l630">630</a><td>var Arrays = goog.require(&#39;goog.array&#39;);<tr><td><a id="l631"></a><a href="#l631">631</a><td>var asserts = goog.require(&#39;goog.asserts&#39;);<tr><td><a id="l632"></a><a href="#l632">632</a><td>var asyncRun = goog.require(&#39;goog.async.run&#39;);<tr><td><a id="l633"></a><a href="#l633">633</a><td>var throwException = goog.require(&#39;goog.async.throwException&#39;);<tr><td><a id="l634"></a><a href="#l634">634</a><td>var DebugError = goog.require(&#39;goog.debug.Error&#39;);<tr><td><a id="l635"></a><a href="#l635">635</a><td>var log = goog.require(&#39;goog.log&#39;);<tr><td><a id="l636"></a><a href="#l636">636</a><td>var Objects = goog.require(&#39;goog.object&#39;);<tr><td><a id="l637"></a><a href="#l637">637</a><td>var EventEmitter = goog.require(&#39;webdriver.EventEmitter&#39;);<tr><td><a id="l638"></a><a href="#l638">638</a><td>var stacktrace = goog.require(&#39;webdriver.stacktrace&#39;);<tr><td><a id="l639"></a><a href="#l639">639</a><td><tr><td><a id="l640"></a><a href="#l640">640</a><td><tr><td><a id="l641"></a><a href="#l641">641</a><td><tr><td><a id="l642"></a><a href="#l642">642</a><td>/**<tr><td><a id="l643"></a><a href="#l643">643</a><td> * @define {boolean} Whether to append traces of {@code then} to rejection<tr><td><a id="l644"></a><a href="#l644">644</a><td> * errors.<tr><td><a id="l645"></a><a href="#l645">645</a><td> */<tr><td><a id="l646"></a><a href="#l646">646</a><td>goog.define(&#39;webdriver.promise.LONG_STACK_TRACES&#39;, false);<tr><td><a id="l647"></a><a href="#l647">647</a><td><tr><td><a id="l648"></a><a href="#l648">648</a><td>/** @const */<tr><td><a id="l649"></a><a href="#l649">649</a><td>var promise = exports;<tr><td><a id="l650"></a><a href="#l650">650</a><td><tr><td><a id="l651"></a><a href="#l651">651</a><td><tr><td><a id="l652"></a><a href="#l652">652</a><td>/** @const */<tr><td><a id="l653"></a><a href="#l653">653</a><td>var LOG = log.getLogger(&#39;webdriver.promise&#39;);<tr><td><a id="l654"></a><a href="#l654">654</a><td><tr><td><a id="l655"></a><a href="#l655">655</a><td><tr><td><a id="l656"></a><a href="#l656">656</a><td>/**<tr><td><a id="l657"></a><a href="#l657">657</a><td> * @param {number} level What level of verbosity to log with.<tr><td><a id="l658"></a><a href="#l658">658</a><td> * @param {(string|function(this: T): string)} loggable The message to log.<tr><td><a id="l659"></a><a href="#l659">659</a><td> * @param {T=} opt_self The object in whose context to run the loggable<tr><td><a id="l660"></a><a href="#l660">660</a><td> * function.<tr><td><a id="l661"></a><a href="#l661">661</a><td> * @template T<tr><td><a id="l662"></a><a href="#l662">662</a><td> */<tr><td><a id="l663"></a><a href="#l663">663</a><td>function vlog(level, loggable, opt_self) {<tr><td><a id="l664"></a><a href="#l664">664</a><td> var logLevel = log.Level.FINE;<tr><td><a id="l665"></a><a href="#l665">665</a><td> if (level &gt; 1) {<tr><td><a id="l666"></a><a href="#l666">666</a><td> logLevel = log.Level.FINEST;<tr><td><a id="l667"></a><a href="#l667">667</a><td> } else if (level &gt; 0) {<tr><td><a id="l668"></a><a href="#l668">668</a><td> logLevel = log.Level.FINER;<tr><td><a id="l669"></a><a href="#l669">669</a><td> }<tr><td><a id="l670"></a><a href="#l670">670</a><td><tr><td><a id="l671"></a><a href="#l671">671</a><td> if (typeof loggable === &#39;function&#39;) {<tr><td><a id="l672"></a><a href="#l672">672</a><td> loggable = loggable.bind(opt_self);<tr><td><a id="l673"></a><a href="#l673">673</a><td> }<tr><td><a id="l674"></a><a href="#l674">674</a><td><tr><td><a id="l675"></a><a href="#l675">675</a><td> log.log(LOG, logLevel, loggable);<tr><td><a id="l676"></a><a href="#l676">676</a><td>}<tr><td><a id="l677"></a><a href="#l677">677</a><td><tr><td><a id="l678"></a><a href="#l678">678</a><td><tr><td><a id="l679"></a><a href="#l679">679</a><td>/**<tr><td><a id="l680"></a><a href="#l680">680</a><td> * Generates an error to capture the current stack trace.<tr><td><a id="l681"></a><a href="#l681">681</a><td> * @param {string} name Error name for this stack trace.<tr><td><a id="l682"></a><a href="#l682">682</a><td> * @param {string} msg Message to record.<tr><td><a id="l683"></a><a href="#l683">683</a><td> * @param {!Function} topFn The function that should appear at the top of the<tr><td><a id="l684"></a><a href="#l684">684</a><td> * stack; only applicable in V8.<tr><td><a id="l685"></a><a href="#l685">685</a><td> * @return {!Error} The generated error.<tr><td><a id="l686"></a><a href="#l686">686</a><td> */<tr><td><a id="l687"></a><a href="#l687">687</a><td>promise.captureStackTrace = function(name, msg, topFn) {<tr><td><a id="l688"></a><a href="#l688">688</a><td> var e = Error(msg);<tr><td><a id="l689"></a><a href="#l689">689</a><td> e.name = name;<tr><td><a id="l690"></a><a href="#l690">690</a><td> if (Error.captureStackTrace) {<tr><td><a id="l691"></a><a href="#l691">691</a><td> Error.captureStackTrace(e, topFn);<tr><td><a id="l692"></a><a href="#l692">692</a><td> } else {<tr><td><a id="l693"></a><a href="#l693">693</a><td> var stack = stacktrace.getStack(e);<tr><td><a id="l694"></a><a href="#l694">694</a><td> e.stack = e.toString();<tr><td><a id="l695"></a><a href="#l695">695</a><td> if (stack) {<tr><td><a id="l696"></a><a href="#l696">696</a><td> e.stack += &#39;\n&#39; + stack;<tr><td><a id="l697"></a><a href="#l697">697</a><td> }<tr><td><a id="l698"></a><a href="#l698">698</a><td> }<tr><td><a id="l699"></a><a href="#l699">699</a><td> return e;<tr><td><a id="l700"></a><a href="#l700">700</a><td>};<tr><td><a id="l701"></a><a href="#l701">701</a><td><tr><td><a id="l702"></a><a href="#l702">702</a><td><tr><td><a id="l703"></a><a href="#l703">703</a><td>/**<tr><td><a id="l704"></a><a href="#l704">704</a><td> * Error used when the computation of a promise is cancelled.<tr><td><a id="l705"></a><a href="#l705">705</a><td> *<tr><td><a id="l706"></a><a href="#l706">706</a><td> * @unrestricted<tr><td><a id="l707"></a><a href="#l707">707</a><td> */<tr><td><a id="l708"></a><a href="#l708">708</a><td>promise.CancellationError = goog.defineClass(DebugError, {<tr><td><a id="l709"></a><a href="#l709">709</a><td> /**<tr><td><a id="l710"></a><a href="#l710">710</a><td> * @param {string=} opt_msg The cancellation message.<tr><td><a id="l711"></a><a href="#l711">711</a><td> */<tr><td><a id="l712"></a><a href="#l712">712</a><td> constructor: function(opt_msg) {<tr><td><a id="l713"></a><a href="#l713">713</a><td> promise.CancellationError.base(this, &#39;constructor&#39;, opt_msg);<tr><td><a id="l714"></a><a href="#l714">714</a><td><tr><td><a id="l715"></a><a href="#l715">715</a><td> /** @override */<tr><td><a id="l716"></a><a href="#l716">716</a><td> this.name = &#39;CancellationError&#39;;<tr><td><a id="l717"></a><a href="#l717">717</a><td><tr><td><a id="l718"></a><a href="#l718">718</a><td> /** @private {boolean} */<tr><td><a id="l719"></a><a href="#l719">719</a><td> this.silent_ = false;<tr><td><a id="l720"></a><a href="#l720">720</a><td> },<tr><td><a id="l721"></a><a href="#l721">721</a><td><tr><td><a id="l722"></a><a href="#l722">722</a><td> statics: {<tr><td><a id="l723"></a><a href="#l723">723</a><td> /**<tr><td><a id="l724"></a><a href="#l724">724</a><td> * Wraps the given error in a CancellationError.<tr><td><a id="l725"></a><a href="#l725">725</a><td> *<tr><td><a id="l726"></a><a href="#l726">726</a><td> * @param {*} error The error to wrap.<tr><td><a id="l727"></a><a href="#l727">727</a><td> * @param {string=} opt_msg The prefix message to use.<tr><td><a id="l728"></a><a href="#l728">728</a><td> * @return {!promise.CancellationError} A cancellation error.<tr><td><a id="l729"></a><a href="#l729">729</a><td> */<tr><td><a id="l730"></a><a href="#l730">730</a><td> wrap: function(error, opt_msg) {<tr><td><a id="l731"></a><a href="#l731">731</a><td> var message;<tr><td><a id="l732"></a><a href="#l732">732</a><td> if (error instanceof promise.CancellationError) {<tr><td><a id="l733"></a><a href="#l733">733</a><td> return new promise.CancellationError(<tr><td><a id="l734"></a><a href="#l734">734</a><td> opt_msg ? (opt_msg + &#39;: &#39; + error.message) : error.message);<tr><td><a id="l735"></a><a href="#l735">735</a><td> } else if (opt_msg) {<tr><td><a id="l736"></a><a href="#l736">736</a><td> message = opt_msg;<tr><td><a id="l737"></a><a href="#l737">737</a><td> if (error) {<tr><td><a id="l738"></a><a href="#l738">738</a><td> message += &#39;: &#39; + error;<tr><td><a id="l739"></a><a href="#l739">739</a><td> }<tr><td><a id="l740"></a><a href="#l740">740</a><td> return new promise.CancellationError(message);<tr><td><a id="l741"></a><a href="#l741">741</a><td> }<tr><td><a id="l742"></a><a href="#l742">742</a><td> if (error) {<tr><td><a id="l743"></a><a href="#l743">743</a><td> message = error + &#39;&#39;;<tr><td><a id="l744"></a><a href="#l744">744</a><td> }<tr><td><a id="l745"></a><a href="#l745">745</a><td> return new promise.CancellationError(message);<tr><td><a id="l746"></a><a href="#l746">746</a><td> }<tr><td><a id="l747"></a><a href="#l747">747</a><td> }<tr><td><a id="l748"></a><a href="#l748">748</a><td>});<tr><td><a id="l749"></a><a href="#l749">749</a><td><tr><td><a id="l750"></a><a href="#l750">750</a><td><tr><td><a id="l751"></a><a href="#l751">751</a><td>/**<tr><td><a id="l752"></a><a href="#l752">752</a><td> * Error used to cancel tasks when a control flow is reset.<tr><td><a id="l753"></a><a href="#l753">753</a><td> * @unrestricted<tr><td><a id="l754"></a><a href="#l754">754</a><td> * @final<tr><td><a id="l755"></a><a href="#l755">755</a><td> */<tr><td><a id="l756"></a><a href="#l756">756</a><td>var FlowResetError = goog.defineClass(promise.CancellationError, {<tr><td><a id="l757"></a><a href="#l757">757</a><td> constructor: function() {<tr><td><a id="l758"></a><a href="#l758">758</a><td> FlowResetError.base(this, &#39;constructor&#39;, &#39;ControlFlow was reset&#39;);<tr><td><a id="l759"></a><a href="#l759">759</a><td><tr><td><a id="l760"></a><a href="#l760">760</a><td> /** @override */<tr><td><a id="l761"></a><a href="#l761">761</a><td> this.name = &#39;FlowResetError&#39;;<tr><td><a id="l762"></a><a href="#l762">762</a><td><tr><td><a id="l763"></a><a href="#l763">763</a><td> this.silent_ = true;<tr><td><a id="l764"></a><a href="#l764">764</a><td> }<tr><td><a id="l765"></a><a href="#l765">765</a><td>});<tr><td><a id="l766"></a><a href="#l766">766</a><td><tr><td><a id="l767"></a><a href="#l767">767</a><td><tr><td><a id="l768"></a><a href="#l768">768</a><td>/**<tr><td><a id="l769"></a><a href="#l769">769</a><td> * Error used to cancel tasks that have been discarded due to an uncaught error<tr><td><a id="l770"></a><a href="#l770">770</a><td> * reported earlier in the control flow.<tr><td><a id="l771"></a><a href="#l771">771</a><td> * @unrestricted<tr><td><a id="l772"></a><a href="#l772">772</a><td> * @final<tr><td><a id="l773"></a><a href="#l773">773</a><td> */<tr><td><a id="l774"></a><a href="#l774">774</a><td>var DiscardedTaskError = goog.defineClass(promise.CancellationError, {<tr><td><a id="l775"></a><a href="#l775">775</a><td> /** @param {*} error The original error. */<tr><td><a id="l776"></a><a href="#l776">776</a><td> constructor: function(error) {<tr><td><a id="l777"></a><a href="#l777">777</a><td> if (error instanceof DiscardedTaskError) {<tr><td><a id="l778"></a><a href="#l778">778</a><td> return /** @type {!DiscardedTaskError} */(error);<tr><td><a id="l779"></a><a href="#l779">779</a><td> }<tr><td><a id="l780"></a><a href="#l780">780</a><td><tr><td><a id="l781"></a><a href="#l781">781</a><td> var msg = &#39;&#39;;<tr><td><a id="l782"></a><a href="#l782">782</a><td> if (error) {<tr><td><a id="l783"></a><a href="#l783">783</a><td> msg = &#39;: &#39; + (typeof error.message === &#39;string&#39; ? error.message : error);<tr><td><a id="l784"></a><a href="#l784">784</a><td> }<tr><td><a id="l785"></a><a href="#l785">785</a><td><tr><td><a id="l786"></a><a href="#l786">786</a><td> DiscardedTaskError.base(this, &#39;constructor&#39;,<tr><td><a id="l787"></a><a href="#l787">787</a><td> &#39;Task was discarded due to a previous failure&#39; + msg);<tr><td><a id="l788"></a><a href="#l788">788</a><td><tr><td><a id="l789"></a><a href="#l789">789</a><td> /** @override */<tr><td><a id="l790"></a><a href="#l790">790</a><td> this.name = &#39;DiscardedTaskError&#39;;<tr><td><a id="l791"></a><a href="#l791">791</a><td> this.silent_ = true;<tr><td><a id="l792"></a><a href="#l792">792</a><td> }<tr><td><a id="l793"></a><a href="#l793">793</a><td>});<tr><td><a id="l794"></a><a href="#l794">794</a><td><tr><td><a id="l795"></a><a href="#l795">795</a><td><tr><td><a id="l796"></a><a href="#l796">796</a><td>/**<tr><td><a id="l797"></a><a href="#l797">797</a><td> * Error used when there are multiple unhandled promise rejections detected<tr><td><a id="l798"></a><a href="#l798">798</a><td> * within a task or callback.<tr><td><a id="l799"></a><a href="#l799">799</a><td> *<tr><td><a id="l800"></a><a href="#l800">800</a><td> * @unrestricted<tr><td><a id="l801"></a><a href="#l801">801</a><td> * @final<tr><td><a id="l802"></a><a href="#l802">802</a><td> */<tr><td><a id="l803"></a><a href="#l803">803</a><td>promise.MultipleUnhandledRejectionError = goog.defineClass(DebugError, {<tr><td><a id="l804"></a><a href="#l804">804</a><td> /**<tr><td><a id="l805"></a><a href="#l805">805</a><td> * @param {!(Set&lt;*&gt;)} errors The errors to report.<tr><td><a id="l806"></a><a href="#l806">806</a><td> */<tr><td><a id="l807"></a><a href="#l807">807</a><td> constructor: function(errors) {<tr><td><a id="l808"></a><a href="#l808">808</a><td> promise.MultipleUnhandledRejectionError.base(<tr><td><a id="l809"></a><a href="#l809">809</a><td> this, &#39;constructor&#39;, &#39;Multiple unhandled promise rejections reported&#39;);<tr><td><a id="l810"></a><a href="#l810">810</a><td><tr><td><a id="l811"></a><a href="#l811">811</a><td> /** @override */<tr><td><a id="l812"></a><a href="#l812">812</a><td> this.name = &#39;MultipleUnhandledRejectionError&#39;;<tr><td><a id="l813"></a><a href="#l813">813</a><td><tr><td><a id="l814"></a><a href="#l814">814</a><td> /** @type {!Set&lt;*&gt;} */<tr><td><a id="l815"></a><a href="#l815">815</a><td> this.errors = errors;<tr><td><a id="l816"></a><a href="#l816">816</a><td> }<tr><td><a id="l817"></a><a href="#l817">817</a><td>});<tr><td><a id="l818"></a><a href="#l818">818</a><td><tr><td><a id="l819"></a><a href="#l819">819</a><td><tr><td><a id="l820"></a><a href="#l820">820</a><td>/**<tr><td><a id="l821"></a><a href="#l821">821</a><td> * Property used to flag constructor&#39;s as implementing the Thenable interface<tr><td><a id="l822"></a><a href="#l822">822</a><td> * for runtime type checking.<tr><td><a id="l823"></a><a href="#l823">823</a><td> * @type {string}<tr><td><a id="l824"></a><a href="#l824">824</a><td> * @const<tr><td><a id="l825"></a><a href="#l825">825</a><td> */<tr><td><a id="l826"></a><a href="#l826">826</a><td>var IMPLEMENTED_BY_PROP = &#39;$webdriver_Thenable&#39;;<tr><td><a id="l827"></a><a href="#l827">827</a><td><tr><td><a id="l828"></a><a href="#l828">828</a><td><tr><td><a id="l829"></a><a href="#l829">829</a><td>/**<tr><td><a id="l830"></a><a href="#l830">830</a><td> * Thenable is a promise-like object with a {@code then} method which may be<tr><td><a id="l831"></a><a href="#l831">831</a><td> * used to schedule callbacks on a promised value.<tr><td><a id="l832"></a><a href="#l832">832</a><td> *<tr><td><a id="l833"></a><a href="#l833">833</a><td> * @interface<tr><td><a id="l834"></a><a href="#l834">834</a><td> * @extends {IThenable&lt;T&gt;}<tr><td><a id="l835"></a><a href="#l835">835</a><td> * @template T<tr><td><a id="l836"></a><a href="#l836">836</a><td> */<tr><td><a id="l837"></a><a href="#l837">837</a><td>promise.Thenable = goog.defineClass(null, {<tr><td><a id="l838"></a><a href="#l838">838</a><td> statics: {<tr><td><a id="l839"></a><a href="#l839">839</a><td> /**<tr><td><a id="l840"></a><a href="#l840">840</a><td> * Adds a property to a class prototype to allow runtime checks of whether<tr><td><a id="l841"></a><a href="#l841">841</a><td> * instances of that class implement the Thenable interface. This function<tr><td><a id="l842"></a><a href="#l842">842</a><td> * will also ensure the prototype&#39;s {@code then} function is exported from<tr><td><a id="l843"></a><a href="#l843">843</a><td> * compiled code.<tr><td><a id="l844"></a><a href="#l844">844</a><td> * @param {function(new: promise.Thenable, ...?)} ctor The<tr><td><a id="l845"></a><a href="#l845">845</a><td> * constructor whose prototype to modify.<tr><td><a id="l846"></a><a href="#l846">846</a><td> */<tr><td><a id="l847"></a><a href="#l847">847</a><td> addImplementation: function(ctor) {<tr><td><a id="l848"></a><a href="#l848">848</a><td> // Based on goog.promise.Thenable.isImplementation.<tr><td><a id="l849"></a><a href="#l849">849</a><td> ctor.prototype[&#39;then&#39;] = ctor.prototype.then;<tr><td><a id="l850"></a><a href="#l850">850</a><td> try {<tr><td><a id="l851"></a><a href="#l851">851</a><td> // Old IE7 does not support defineProperty; IE8 only supports it for<tr><td><a id="l852"></a><a href="#l852">852</a><td> // DOM elements.<tr><td><a id="l853"></a><a href="#l853">853</a><td> Object.defineProperty(<tr><td><a id="l854"></a><a href="#l854">854</a><td> ctor.prototype,<tr><td><a id="l855"></a><a href="#l855">855</a><td> IMPLEMENTED_BY_PROP,<tr><td><a id="l856"></a><a href="#l856">856</a><td> {&#39;value&#39;: true, &#39;enumerable&#39;: false});<tr><td><a id="l857"></a><a href="#l857">857</a><td> } catch (ex) {<tr><td><a id="l858"></a><a href="#l858">858</a><td> ctor.prototype[IMPLEMENTED_BY_PROP] = true;<tr><td><a id="l859"></a><a href="#l859">859</a><td> }<tr><td><a id="l860"></a><a href="#l860">860</a><td> },<tr><td><a id="l861"></a><a href="#l861">861</a><td><tr><td><a id="l862"></a><a href="#l862">862</a><td> /**<tr><td><a id="l863"></a><a href="#l863">863</a><td> * Checks if an object has been tagged for implementing the Thenable<tr><td><a id="l864"></a><a href="#l864">864</a><td> * interface as defined by<tr><td><a id="l865"></a><a href="#l865">865</a><td> * {@link webdriver.promise.Thenable.addImplementation}.<tr><td><a id="l866"></a><a href="#l866">866</a><td> * @param {*} object The object to test.<tr><td><a id="l867"></a><a href="#l867">867</a><td> * @return {boolean} Whether the object is an implementation of the Thenable<tr><td><a id="l868"></a><a href="#l868">868</a><td> * interface.<tr><td><a id="l869"></a><a href="#l869">869</a><td> */<tr><td><a id="l870"></a><a href="#l870">870</a><td> isImplementation: function(object) {<tr><td><a id="l871"></a><a href="#l871">871</a><td> // Based on goog.promise.Thenable.isImplementation.<tr><td><a id="l872"></a><a href="#l872">872</a><td> if (!object) {<tr><td><a id="l873"></a><a href="#l873">873</a><td> return false;<tr><td><a id="l874"></a><a href="#l874">874</a><td> }<tr><td><a id="l875"></a><a href="#l875">875</a><td> try {<tr><td><a id="l876"></a><a href="#l876">876</a><td> return !!object[IMPLEMENTED_BY_PROP];<tr><td><a id="l877"></a><a href="#l877">877</a><td> } catch (e) {<tr><td><a id="l878"></a><a href="#l878">878</a><td> return false; // Property access seems to be forbidden.<tr><td><a id="l879"></a><a href="#l879">879</a><td> }<tr><td><a id="l880"></a><a href="#l880">880</a><td> }<tr><td><a id="l881"></a><a href="#l881">881</a><td> },<tr><td><a id="l882"></a><a href="#l882">882</a><td><tr><td><a id="l883"></a><a href="#l883">883</a><td> /**<tr><td><a id="l884"></a><a href="#l884">884</a><td> * Cancels the computation of this promise&#39;s value, rejecting the promise in<tr><td><a id="l885"></a><a href="#l885">885</a><td> * the process. This method is a no-op if the promise has already been<tr><td><a id="l886"></a><a href="#l886">886</a><td> * resolved.<tr><td><a id="l887"></a><a href="#l887">887</a><td> *<tr><td><a id="l888"></a><a href="#l888">888</a><td> * @param {(string|promise.CancellationError)=} opt_reason The reason this<tr><td><a id="l889"></a><a href="#l889">889</a><td> * promise is being cancelled.<tr><td><a id="l890"></a><a href="#l890">890</a><td> */<tr><td><a id="l891"></a><a href="#l891">891</a><td> cancel: function(opt_reason) {},<tr><td><a id="l892"></a><a href="#l892">892</a><td><tr><td><a id="l893"></a><a href="#l893">893</a><td> /** @return {boolean} Whether this promise&#39;s value is still being computed. */<tr><td><a id="l894"></a><a href="#l894">894</a><td> isPending: function() {},<tr><td><a id="l895"></a><a href="#l895">895</a><td><tr><td><a id="l896"></a><a href="#l896">896</a><td> /**<tr><td><a id="l897"></a><a href="#l897">897</a><td> * Registers listeners for when this instance is resolved.<tr><td><a id="l898"></a><a href="#l898">898</a><td> *<tr><td><a id="l899"></a><a href="#l899">899</a><td> * @param {?(function(T): (R|IThenable&lt;R&gt;))=} opt_callback The<tr><td><a id="l900"></a><a href="#l900">900</a><td> * function to call if this promise is successfully resolved. The function<tr><td><a id="l901"></a><a href="#l901">901</a><td> * should expect a single argument: the promise&#39;s resolved value.<tr><td><a id="l902"></a><a href="#l902">902</a><td> * @param {?(function(*): (R|IThenable&lt;R&gt;))=} opt_errback<tr><td><a id="l903"></a><a href="#l903">903</a><td> * The function to call if this promise is rejected. The function should<tr><td><a id="l904"></a><a href="#l904">904</a><td> * expect a single argument: the rejection reason.<tr><td><a id="l905"></a><a href="#l905">905</a><td> * @return {!promise.Promise&lt;R&gt;} A new promise which will be<tr><td><a id="l906"></a><a href="#l906">906</a><td> * resolved with the result of the invoked callback.<tr><td><a id="l907"></a><a href="#l907">907</a><td> * @template R<tr><td><a id="l908"></a><a href="#l908">908</a><td> */<tr><td><a id="l909"></a><a href="#l909">909</a><td> then: function(opt_callback, opt_errback) {},<tr><td><a id="l910"></a><a href="#l910">910</a><td><tr><td><a id="l911"></a><a href="#l911">911</a><td> /**<tr><td><a id="l912"></a><a href="#l912">912</a><td> * Registers a listener for when this promise is rejected. This is synonymous<tr><td><a id="l913"></a><a href="#l913">913</a><td> * with the {@code catch} clause in a synchronous API:<tr><td><a id="l914"></a><a href="#l914">914</a><td> *<tr><td><a id="l915"></a><a href="#l915">915</a><td> * // Synchronous API:<tr><td><a id="l916"></a><a href="#l916">916</a><td> * try {<tr><td><a id="l917"></a><a href="#l917">917</a><td> * doSynchronousWork();<tr><td><a id="l918"></a><a href="#l918">918</a><td> * } catch (ex) {<tr><td><a id="l919"></a><a href="#l919">919</a><td> * console.error(ex);<tr><td><a id="l920"></a><a href="#l920">920</a><td> * }<tr><td><a id="l921"></a><a href="#l921">921</a><td> *<tr><td><a id="l922"></a><a href="#l922">922</a><td> * // Asynchronous promise API:<tr><td><a id="l923"></a><a href="#l923">923</a><td> * doAsynchronousWork().thenCatch(function(ex) {<tr><td><a id="l924"></a><a href="#l924">924</a><td> * console.error(ex);<tr><td><a id="l925"></a><a href="#l925">925</a><td> * });<tr><td><a id="l926"></a><a href="#l926">926</a><td> *<tr><td><a id="l927"></a><a href="#l927">927</a><td> * @param {function(*): (R|IThenable&lt;R&gt;)} errback The<tr><td><a id="l928"></a><a href="#l928">928</a><td> * function to call if this promise is rejected. The function should<tr><td><a id="l929"></a><a href="#l929">929</a><td> * expect a single argument: the rejection reason.<tr><td><a id="l930"></a><a href="#l930">930</a><td> * @return {!promise.Promise&lt;R&gt;} A new promise which will be<tr><td><a id="l931"></a><a href="#l931">931</a><td> * resolved with the result of the invoked callback.<tr><td><a id="l932"></a><a href="#l932">932</a><td> * @template R<tr><td><a id="l933"></a><a href="#l933">933</a><td> */<tr><td><a id="l934"></a><a href="#l934">934</a><td> thenCatch: function(errback) {},<tr><td><a id="l935"></a><a href="#l935">935</a><td><tr><td><a id="l936"></a><a href="#l936">936</a><td> /**<tr><td><a id="l937"></a><a href="#l937">937</a><td> * Registers a listener to invoke when this promise is resolved, regardless<tr><td><a id="l938"></a><a href="#l938">938</a><td> * of whether the promise&#39;s value was successfully computed. This function<tr><td><a id="l939"></a><a href="#l939">939</a><td> * is synonymous with the {@code finally} clause in a synchronous API:<tr><td><a id="l940"></a><a href="#l940">940</a><td> *<tr><td><a id="l941"></a><a href="#l941">941</a><td> * // Synchronous API:<tr><td><a id="l942"></a><a href="#l942">942</a><td> * try {<tr><td><a id="l943"></a><a href="#l943">943</a><td> * doSynchronousWork();<tr><td><a id="l944"></a><a href="#l944">944</a><td> * } finally {<tr><td><a id="l945"></a><a href="#l945">945</a><td> * cleanUp();<tr><td><a id="l946"></a><a href="#l946">946</a><td> * }<tr><td><a id="l947"></a><a href="#l947">947</a><td> *<tr><td><a id="l948"></a><a href="#l948">948</a><td> * // Asynchronous promise API:<tr><td><a id="l949"></a><a href="#l949">949</a><td> * doAsynchronousWork().thenFinally(cleanUp);<tr><td><a id="l950"></a><a href="#l950">950</a><td> *<tr><td><a id="l951"></a><a href="#l951">951</a><td> * __Note:__ similar to the {@code finally} clause, if the registered<tr><td><a id="l952"></a><a href="#l952">952</a><td> * callback returns a rejected promise or throws an error, it will silently<tr><td><a id="l953"></a><a href="#l953">953</a><td> * replace the rejection error (if any) from this promise:<tr><td><a id="l954"></a><a href="#l954">954</a><td> *<tr><td><a id="l955"></a><a href="#l955">955</a><td> * try {<tr><td><a id="l956"></a><a href="#l956">956</a><td> * throw Error(&#39;one&#39;);<tr><td><a id="l957"></a><a href="#l957">957</a><td> * } finally {<tr><td><a id="l958"></a><a href="#l958">958</a><td> * throw Error(&#39;two&#39;); // Hides Error: one<tr><td><a id="l959"></a><a href="#l959">959</a><td> * }<tr><td><a id="l960"></a><a href="#l960">960</a><td> *<tr><td><a id="l961"></a><a href="#l961">961</a><td> * promise.rejected(Error(&#39;one&#39;))<tr><td><a id="l962"></a><a href="#l962">962</a><td> * .thenFinally(function() {<tr><td><a id="l963"></a><a href="#l963">963</a><td> * throw Error(&#39;two&#39;); // Hides Error: one<tr><td><a id="l964"></a><a href="#l964">964</a><td> * });<tr><td><a id="l965"></a><a href="#l965">965</a><td> *<tr><td><a id="l966"></a><a href="#l966">966</a><td> * @param {function(): (R|IThenable&lt;R&gt;)} callback The function<tr><td><a id="l967"></a><a href="#l967">967</a><td> * to call when this promise is resolved.<tr><td><a id="l968"></a><a href="#l968">968</a><td> * @return {!promise.Promise&lt;R&gt;} A promise that will be fulfilled<tr><td><a id="l969"></a><a href="#l969">969</a><td> * with the callback result.<tr><td><a id="l970"></a><a href="#l970">970</a><td> * @template R<tr><td><a id="l971"></a><a href="#l971">971</a><td> */<tr><td><a id="l972"></a><a href="#l972">972</a><td> thenFinally: function(callback) {}<tr><td><a id="l973"></a><a href="#l973">973</a><td>});<tr><td><a id="l974"></a><a href="#l974">974</a><td><tr><td><a id="l975"></a><a href="#l975">975</a><td><tr><td><a id="l976"></a><a href="#l976">976</a><td><tr><td><a id="l977"></a><a href="#l977">977</a><td>/**<tr><td><a id="l978"></a><a href="#l978">978</a><td> * @enum {string}<tr><td><a id="l979"></a><a href="#l979">979</a><td> */<tr><td><a id="l980"></a><a href="#l980">980</a><td>var PromiseState = {<tr><td><a id="l981"></a><a href="#l981">981</a><td> PENDING: &#39;pending&#39;,<tr><td><a id="l982"></a><a href="#l982">982</a><td> BLOCKED: &#39;blocked&#39;,<tr><td><a id="l983"></a><a href="#l983">983</a><td> REJECTED: &#39;rejected&#39;,<tr><td><a id="l984"></a><a href="#l984">984</a><td> FULFILLED: &#39;fulfilled&#39;<tr><td><a id="l985"></a><a href="#l985">985</a><td>};<tr><td><a id="l986"></a><a href="#l986">986</a><td><tr><td><a id="l987"></a><a href="#l987">987</a><td><tr><td><a id="l988"></a><a href="#l988">988</a><td>/**<tr><td><a id="l989"></a><a href="#l989">989</a><td> * Internal symbol used to store a cancellation handler for<tr><td><a id="l990"></a><a href="#l990">990</a><td> * {@link promise.Promise} objects. This is an internal implementation detail<tr><td><a id="l991"></a><a href="#l991">991</a><td> * used by the {@link TaskQueue} class to monitor for when a promise is<tr><td><a id="l992"></a><a href="#l992">992</a><td> * cancelled without generating an extra promise via then().<tr><td><a id="l993"></a><a href="#l993">993</a><td> */<tr><td><a id="l994"></a><a href="#l994">994</a><td>var CANCEL_HANDLER_SYMBOL = Symbol(&#39;on cancel&#39;);<tr><td><a id="l995"></a><a href="#l995">995</a><td><tr><td><a id="l996"></a><a href="#l996">996</a><td><tr><td><a id="l997"></a><a href="#l997">997</a><td>/**<tr><td><a id="l998"></a><a href="#l998">998</a><td> * Represents the eventual value of a completed operation. Each promise may be<tr><td><a id="l999"></a><a href="#l999">999</a><td> * in one of three states: pending, fulfilled, or rejected. Each promise starts<tr><td><a id="l1000"></a><a href="#l1000">1000</a><td> * in the pending state and may make a single transition to either a<tr><td><a id="l1001"></a><a href="#l1001">1001</a><td> * fulfilled or rejected state, at which point the promise is considered<tr><td><a id="l1002"></a><a href="#l1002">1002</a><td> * resolved.<tr><td><a id="l1003"></a><a href="#l1003">1003</a><td> *<tr><td><a id="l1004"></a><a href="#l1004">1004</a><td> * @implements {promise.Thenable&lt;T&gt;}<tr><td><a id="l1005"></a><a href="#l1005">1005</a><td> * @template T<tr><td><a id="l1006"></a><a href="#l1006">1006</a><td> * @see http://promises-aplus.github.io/promises-spec/<tr><td><a id="l1007"></a><a href="#l1007">1007</a><td> * @unrestricted // For using CANCEL_HANDLER_SYMBOL.<tr><td><a id="l1008"></a><a href="#l1008">1008</a><td> */<tr><td><a id="l1009"></a><a href="#l1009">1009</a><td>promise.Promise = goog.defineClass(null, {<tr><td><a id="l1010"></a><a href="#l1010">1010</a><td> /**<tr><td><a id="l1011"></a><a href="#l1011">1011</a><td> * @param {function(<tr><td><a id="l1012"></a><a href="#l1012">1012</a><td> * function((T|IThenable&lt;T&gt;|Thenable)=),<tr><td><a id="l1013"></a><a href="#l1013">1013</a><td> * function(*=))} resolver<tr><td><a id="l1014"></a><a href="#l1014">1014</a><td> * Function that is invoked immediately to begin computation of this<tr><td><a id="l1015"></a><a href="#l1015">1015</a><td> * promise&#39;s value. The function should accept a pair of callback<tr><td><a id="l1016"></a><a href="#l1016">1016</a><td> * functions, one for fulfilling the promise and another for rejecting it.<tr><td><a id="l1017"></a><a href="#l1017">1017</a><td> * @param {promise.ControlFlow=} opt_flow The control flow<tr><td><a id="l1018"></a><a href="#l1018">1018</a><td> * this instance was created under. Defaults to the currently active flow.<tr><td><a id="l1019"></a><a href="#l1019">1019</a><td> */<tr><td><a id="l1020"></a><a href="#l1020">1020</a><td> constructor: function(resolver, opt_flow) {<tr><td><a id="l1021"></a><a href="#l1021">1021</a><td> goog.getUid(this);<tr><td><a id="l1022"></a><a href="#l1022">1022</a><td><tr><td><a id="l1023"></a><a href="#l1023">1023</a><td> /** @private {!promise.ControlFlow} */<tr><td><a id="l1024"></a><a href="#l1024">1024</a><td> this.flow_ = opt_flow || promise.controlFlow();<tr><td><a id="l1025"></a><a href="#l1025">1025</a><td><tr><td><a id="l1026"></a><a href="#l1026">1026</a><td> /** @private {Error} */<tr><td><a id="l1027"></a><a href="#l1027">1027</a><td> this.stack_ = null;<tr><td><a id="l1028"></a><a href="#l1028">1028</a><td> if (promise.LONG_STACK_TRACES) {<tr><td><a id="l1029"></a><a href="#l1029">1029</a><td> this.stack_ = promise.captureStackTrace(<tr><td><a id="l1030"></a><a href="#l1030">1030</a><td> &#39;Promise&#39;, &#39;new&#39;, promise.Promise);<tr><td><a id="l1031"></a><a href="#l1031">1031</a><td> }<tr><td><a id="l1032"></a><a href="#l1032">1032</a><td><tr><td><a id="l1033"></a><a href="#l1033">1033</a><td> /** @private {promise.Promise&lt;?&gt;} */<tr><td><a id="l1034"></a><a href="#l1034">1034</a><td> this.parent_ = null;<tr><td><a id="l1035"></a><a href="#l1035">1035</a><td><tr><td><a id="l1036"></a><a href="#l1036">1036</a><td> /** @private {Array&lt;!Task&gt;} */<tr><td><a id="l1037"></a><a href="#l1037">1037</a><td> this.callbacks_ = null;<tr><td><a id="l1038"></a><a href="#l1038">1038</a><td><tr><td><a id="l1039"></a><a href="#l1039">1039</a><td> /** @private {PromiseState} */<tr><td><a id="l1040"></a><a href="#l1040">1040</a><td> this.state_ = PromiseState.PENDING;<tr><td><a id="l1041"></a><a href="#l1041">1041</a><td><tr><td><a id="l1042"></a><a href="#l1042">1042</a><td> /** @private {boolean} */<tr><td><a id="l1043"></a><a href="#l1043">1043</a><td> this.handled_ = false;<tr><td><a id="l1044"></a><a href="#l1044">1044</a><td><tr><td><a id="l1045"></a><a href="#l1045">1045</a><td> /** @private {*} */<tr><td><a id="l1046"></a><a href="#l1046">1046</a><td> this.value_ = undefined;<tr><td><a id="l1047"></a><a href="#l1047">1047</a><td><tr><td><a id="l1048"></a><a href="#l1048">1048</a><td> /** @private {TaskQueue} */<tr><td><a id="l1049"></a><a href="#l1049">1049</a><td> this.queue_ = null;<tr><td><a id="l1050"></a><a href="#l1050">1050</a><td><tr><td><a id="l1051"></a><a href="#l1051">1051</a><td> /** @private {(function(promise.CancellationError)|null)} */<tr><td><a id="l1052"></a><a href="#l1052">1052</a><td> this[CANCEL_HANDLER_SYMBOL] = null;<tr><td><a id="l1053"></a><a href="#l1053">1053</a><td><tr><td><a id="l1054"></a><a href="#l1054">1054</a><td> try {<tr><td><a id="l1055"></a><a href="#l1055">1055</a><td> var self = this;<tr><td><a id="l1056"></a><a href="#l1056">1056</a><td> resolver(function(value) {<tr><td><a id="l1057"></a><a href="#l1057">1057</a><td> self.resolve_(PromiseState.FULFILLED, value);<tr><td><a id="l1058"></a><a href="#l1058">1058</a><td> }, function(reason) {<tr><td><a id="l1059"></a><a href="#l1059">1059</a><td> self.resolve_(PromiseState.REJECTED, reason);<tr><td><a id="l1060"></a><a href="#l1060">1060</a><td> });<tr><td><a id="l1061"></a><a href="#l1061">1061</a><td> } catch (ex) {<tr><td><a id="l1062"></a><a href="#l1062">1062</a><td> this.resolve_(PromiseState.REJECTED, ex);<tr><td><a id="l1063"></a><a href="#l1063">1063</a><td> }<tr><td><a id="l1064"></a><a href="#l1064">1064</a><td> },<tr><td><a id="l1065"></a><a href="#l1065">1065</a><td><tr><td><a id="l1066"></a><a href="#l1066">1066</a><td> /** @override */<tr><td><a id="l1067"></a><a href="#l1067">1067</a><td> toString: function() {<tr><td><a id="l1068"></a><a href="#l1068">1068</a><td> return &#39;Promise::&#39; + goog.getUid(this) +<tr><td><a id="l1069"></a><a href="#l1069">1069</a><td> &#39; {[[PromiseStatus]]: &quot;&#39; + this.state_ + &#39;&quot;}&#39;;<tr><td><a id="l1070"></a><a href="#l1070">1070</a><td> },<tr><td><a id="l1071"></a><a href="#l1071">1071</a><td><tr><td><a id="l1072"></a><a href="#l1072">1072</a><td> /**<tr><td><a id="l1073"></a><a href="#l1073">1073</a><td> * Resolves this promise. If the new value is itself a promise, this function<tr><td><a id="l1074"></a><a href="#l1074">1074</a><td> * will wait for it to be resolved before notifying the registered listeners.<tr><td><a id="l1075"></a><a href="#l1075">1075</a><td> * @param {PromiseState} newState The promise&#39;s new state.<tr><td><a id="l1076"></a><a href="#l1076">1076</a><td> * @param {*} newValue The promise&#39;s new value.<tr><td><a id="l1077"></a><a href="#l1077">1077</a><td> * @throws {TypeError} If {@code newValue === this}.<tr><td><a id="l1078"></a><a href="#l1078">1078</a><td> * @private<tr><td><a id="l1079"></a><a href="#l1079">1079</a><td> */<tr><td><a id="l1080"></a><a href="#l1080">1080</a><td> resolve_: function(newState, newValue) {<tr><td><a id="l1081"></a><a href="#l1081">1081</a><td> if (PromiseState.PENDING !== this.state_) {<tr><td><a id="l1082"></a><a href="#l1082">1082</a><td> return;<tr><td><a id="l1083"></a><a href="#l1083">1083</a><td> }<tr><td><a id="l1084"></a><a href="#l1084">1084</a><td><tr><td><a id="l1085"></a><a href="#l1085">1085</a><td> if (newValue === this) {<tr><td><a id="l1086"></a><a href="#l1086">1086</a><td> // See promise a+, 2.3.1<tr><td><a id="l1087"></a><a href="#l1087">1087</a><td> // http://promises-aplus.github.io/promises-spec/#point-48<tr><td><a id="l1088"></a><a href="#l1088">1088</a><td> newValue = new TypeError(&#39;A promise may not resolve to itself&#39;);<tr><td><a id="l1089"></a><a href="#l1089">1089</a><td> newState = PromiseState.REJECTED;<tr><td><a id="l1090"></a><a href="#l1090">1090</a><td> }<tr><td><a id="l1091"></a><a href="#l1091">1091</a><td><tr><td><a id="l1092"></a><a href="#l1092">1092</a><td> this.parent_ = null;<tr><td><a id="l1093"></a><a href="#l1093">1093</a><td> this.state_ = PromiseState.BLOCKED;<tr><td><a id="l1094"></a><a href="#l1094">1094</a><td><tr><td><a id="l1095"></a><a href="#l1095">1095</a><td> if (newState !== PromiseState.REJECTED) {<tr><td><a id="l1096"></a><a href="#l1096">1096</a><td> if (promise.Thenable.isImplementation(newValue)) {<tr><td><a id="l1097"></a><a href="#l1097">1097</a><td> // 2.3.2<tr><td><a id="l1098"></a><a href="#l1098">1098</a><td> newValue = /** @type {!promise.Thenable} */(newValue);<tr><td><a id="l1099"></a><a href="#l1099">1099</a><td> newValue.then(<tr><td><a id="l1100"></a><a href="#l1100">1100</a><td> this.unblockAndResolve_.bind(this, PromiseState.FULFILLED),<tr><td><a id="l1101"></a><a href="#l1101">1101</a><td> this.unblockAndResolve_.bind(this, PromiseState.REJECTED));<tr><td><a id="l1102"></a><a href="#l1102">1102</a><td> return;<tr><td><a id="l1103"></a><a href="#l1103">1103</a><td><tr><td><a id="l1104"></a><a href="#l1104">1104</a><td> } else if (goog.isObject(newValue)) {<tr><td><a id="l1105"></a><a href="#l1105">1105</a><td> // 2.3.3<tr><td><a id="l1106"></a><a href="#l1106">1106</a><td><tr><td><a id="l1107"></a><a href="#l1107">1107</a><td> try {<tr><td><a id="l1108"></a><a href="#l1108">1108</a><td> // 2.3.3.1<tr><td><a id="l1109"></a><a href="#l1109">1109</a><td> var then = newValue[&#39;then&#39;];<tr><td><a id="l1110"></a><a href="#l1110">1110</a><td> } catch (e) {<tr><td><a id="l1111"></a><a href="#l1111">1111</a><td> // 2.3.3.2<tr><td><a id="l1112"></a><a href="#l1112">1112</a><td> this.state_ = PromiseState.REJECTED;<tr><td><a id="l1113"></a><a href="#l1113">1113</a><td> this.value_ = e;<tr><td><a id="l1114"></a><a href="#l1114">1114</a><td> this.scheduleNotifications_();<tr><td><a id="l1115"></a><a href="#l1115">1115</a><td> return;<tr><td><a id="l1116"></a><a href="#l1116">1116</a><td> }<tr><td><a id="l1117"></a><a href="#l1117">1117</a><td><tr><td><a id="l1118"></a><a href="#l1118">1118</a><td> // NB: goog.isFunction is loose and will accept instanceof Function.<tr><td><a id="l1119"></a><a href="#l1119">1119</a><td> if (typeof then === &#39;function&#39;) {<tr><td><a id="l1120"></a><a href="#l1120">1120</a><td> // 2.3.3.3<tr><td><a id="l1121"></a><a href="#l1121">1121</a><td> this.invokeThen_(newValue, then);<tr><td><a id="l1122"></a><a href="#l1122">1122</a><td> return;<tr><td><a id="l1123"></a><a href="#l1123">1123</a><td> }<tr><td><a id="l1124"></a><a href="#l1124">1124</a><td> }<tr><td><a id="l1125"></a><a href="#l1125">1125</a><td> }<tr><td><a id="l1126"></a><a href="#l1126">1126</a><td><tr><td><a id="l1127"></a><a href="#l1127">1127</a><td> if (newState === PromiseState.REJECTED &amp;&amp;<tr><td><a id="l1128"></a><a href="#l1128">1128</a><td> isError(newValue) &amp;&amp; newValue.stack &amp;&amp; this.stack_) {<tr><td><a id="l1129"></a><a href="#l1129">1129</a><td> newValue.stack += &#39;\nFrom: &#39; + (this.stack_.stack || this.stack_);<tr><td><a id="l1130"></a><a href="#l1130">1130</a><td> }<tr><td><a id="l1131"></a><a href="#l1131">1131</a><td><tr><td><a id="l1132"></a><a href="#l1132">1132</a><td> // 2.3.3.4 and 2.3.4<tr><td><a id="l1133"></a><a href="#l1133">1133</a><td> this.state_ = newState;<tr><td><a id="l1134"></a><a href="#l1134">1134</a><td> this.value_ = newValue;<tr><td><a id="l1135"></a><a href="#l1135">1135</a><td> this.scheduleNotifications_();<tr><td><a id="l1136"></a><a href="#l1136">1136</a><td> },<tr><td><a id="l1137"></a><a href="#l1137">1137</a><td><tr><td><a id="l1138"></a><a href="#l1138">1138</a><td> /**<tr><td><a id="l1139"></a><a href="#l1139">1139</a><td> * Invokes a thenable&#39;s &quot;then&quot; method according to 2.3.3.3 of the promise<tr><td><a id="l1140"></a><a href="#l1140">1140</a><td> * A+ spec.<tr><td><a id="l1141"></a><a href="#l1141">1141</a><td> * @param {!Object} x The thenable object.<tr><td><a id="l1142"></a><a href="#l1142">1142</a><td> * @param {!Function} then The &quot;then&quot; function to invoke.<tr><td><a id="l1143"></a><a href="#l1143">1143</a><td> * @private<tr><td><a id="l1144"></a><a href="#l1144">1144</a><td> */<tr><td><a id="l1145"></a><a href="#l1145">1145</a><td> invokeThen_: function(x, then) {<tr><td><a id="l1146"></a><a href="#l1146">1146</a><td> var called = false;<tr><td><a id="l1147"></a><a href="#l1147">1147</a><td> var self = this;<tr><td><a id="l1148"></a><a href="#l1148">1148</a><td><tr><td><a id="l1149"></a><a href="#l1149">1149</a><td> var resolvePromise = function(value) {<tr><td><a id="l1150"></a><a href="#l1150">1150</a><td> if (!called) { // 2.3.3.3.3<tr><td><a id="l1151"></a><a href="#l1151">1151</a><td> called = true;<tr><td><a id="l1152"></a><a href="#l1152">1152</a><td> // 2.3.3.3.1<tr><td><a id="l1153"></a><a href="#l1153">1153</a><td> self.unblockAndResolve_(PromiseState.FULFILLED, value);<tr><td><a id="l1154"></a><a href="#l1154">1154</a><td> }<tr><td><a id="l1155"></a><a href="#l1155">1155</a><td> };<tr><td><a id="l1156"></a><a href="#l1156">1156</a><td><tr><td><a id="l1157"></a><a href="#l1157">1157</a><td> var rejectPromise = function(reason) {<tr><td><a id="l1158"></a><a href="#l1158">1158</a><td> if (!called) { // 2.3.3.3.3<tr><td><a id="l1159"></a><a href="#l1159">1159</a><td> called = true;<tr><td><a id="l1160"></a><a href="#l1160">1160</a><td> // 2.3.3.3.2<tr><td><a id="l1161"></a><a href="#l1161">1161</a><td> self.unblockAndResolve_(PromiseState.REJECTED, reason);<tr><td><a id="l1162"></a><a href="#l1162">1162</a><td> }<tr><td><a id="l1163"></a><a href="#l1163">1163</a><td> };<tr><td><a id="l1164"></a><a href="#l1164">1164</a><td><tr><td><a id="l1165"></a><a href="#l1165">1165</a><td> try {<tr><td><a id="l1166"></a><a href="#l1166">1166</a><td> // 2.3.3.3<tr><td><a id="l1167"></a><a href="#l1167">1167</a><td> then.call(x, resolvePromise, rejectPromise);<tr><td><a id="l1168"></a><a href="#l1168">1168</a><td> } catch (e) {<tr><td><a id="l1169"></a><a href="#l1169">1169</a><td> // 2.3.3.3.4.2<tr><td><a id="l1170"></a><a href="#l1170">1170</a><td> rejectPromise(e);<tr><td><a id="l1171"></a><a href="#l1171">1171</a><td> }<tr><td><a id="l1172"></a><a href="#l1172">1172</a><td> },<tr><td><a id="l1173"></a><a href="#l1173">1173</a><td><tr><td><a id="l1174"></a><a href="#l1174">1174</a><td> /**<tr><td><a id="l1175"></a><a href="#l1175">1175</a><td> * @param {PromiseState} newState The promise&#39;s new state.<tr><td><a id="l1176"></a><a href="#l1176">1176</a><td> * @param {*} newValue The promise&#39;s new value.<tr><td><a id="l1177"></a><a href="#l1177">1177</a><td> * @private<tr><td><a id="l1178"></a><a href="#l1178">1178</a><td> */<tr><td><a id="l1179"></a><a href="#l1179">1179</a><td> unblockAndResolve_: function(newState, newValue) {<tr><td><a id="l1180"></a><a href="#l1180">1180</a><td> if (this.state_ === PromiseState.BLOCKED) {<tr><td><a id="l1181"></a><a href="#l1181">1181</a><td> this.state_ = PromiseState.PENDING;<tr><td><a id="l1182"></a><a href="#l1182">1182</a><td> this.resolve_(newState, newValue);<tr><td><a id="l1183"></a><a href="#l1183">1183</a><td> }<tr><td><a id="l1184"></a><a href="#l1184">1184</a><td> },<tr><td><a id="l1185"></a><a href="#l1185">1185</a><td><tr><td><a id="l1186"></a><a href="#l1186">1186</a><td> /**<tr><td><a id="l1187"></a><a href="#l1187">1187</a><td> * @private<tr><td><a id="l1188"></a><a href="#l1188">1188</a><td> */<tr><td><a id="l1189"></a><a href="#l1189">1189</a><td> scheduleNotifications_: function() {<tr><td><a id="l1190"></a><a href="#l1190">1190</a><td> vlog(2, () =&gt; this + &#39; scheduling notifications&#39;, this);<tr><td><a id="l1191"></a><a href="#l1191">1191</a><td><tr><td><a id="l1192"></a><a href="#l1192">1192</a><td> this[CANCEL_HANDLER_SYMBOL] = null;<tr><td><a id="l1193"></a><a href="#l1193">1193</a><td> if (this.value_ instanceof promise.CancellationError<tr><td><a id="l1194"></a><a href="#l1194">1194</a><td> &amp;&amp; this.value_.silent_) {<tr><td><a id="l1195"></a><a href="#l1195">1195</a><td> this.callbacks_ = null;<tr><td><a id="l1196"></a><a href="#l1196">1196</a><td> }<tr><td><a id="l1197"></a><a href="#l1197">1197</a><td><tr><td><a id="l1198"></a><a href="#l1198">1198</a><td> if (!this.queue_) {<tr><td><a id="l1199"></a><a href="#l1199">1199</a><td> this.queue_ = this.flow_.getActiveQueue_();<tr><td><a id="l1200"></a><a href="#l1200">1200</a><td> }<tr><td><a id="l1201"></a><a href="#l1201">1201</a><td><tr><td><a id="l1202"></a><a href="#l1202">1202</a><td> if (!this.handled_ &amp;&amp;<tr><td><a id="l1203"></a><a href="#l1203">1203</a><td> this.state_ === PromiseState.REJECTED &amp;&amp;<tr><td><a id="l1204"></a><a href="#l1204">1204</a><td> !(this.value_ instanceof promise.CancellationError)) {<tr><td><a id="l1205"></a><a href="#l1205">1205</a><td> this.queue_.addUnhandledRejection(this);<tr><td><a id="l1206"></a><a href="#l1206">1206</a><td> }<tr><td><a id="l1207"></a><a href="#l1207">1207</a><td> this.queue_.scheduleCallbacks(this);<tr><td><a id="l1208"></a><a href="#l1208">1208</a><td> },<tr><td><a id="l1209"></a><a href="#l1209">1209</a><td><tr><td><a id="l1210"></a><a href="#l1210">1210</a><td> /** @override */<tr><td><a id="l1211"></a><a href="#l1211">1211</a><td> cancel: function(opt_reason) {<tr><td><a id="l1212"></a><a href="#l1212">1212</a><td> if (!canCancel(this)) {<tr><td><a id="l1213"></a><a href="#l1213">1213</a><td> return;<tr><td><a id="l1214"></a><a href="#l1214">1214</a><td> }<tr><td><a id="l1215"></a><a href="#l1215">1215</a><td><tr><td><a id="l1216"></a><a href="#l1216">1216</a><td> if (this.parent_ &amp;&amp; canCancel(this.parent_)) {<tr><td><a id="l1217"></a><a href="#l1217">1217</a><td> this.parent_.cancel(opt_reason);<tr><td><a id="l1218"></a><a href="#l1218">1218</a><td> } else {<tr><td><a id="l1219"></a><a href="#l1219">1219</a><td> var reason = promise.CancellationError.wrap(opt_reason);<tr><td><a id="l1220"></a><a href="#l1220">1220</a><td> if (this[CANCEL_HANDLER_SYMBOL]) {<tr><td><a id="l1221"></a><a href="#l1221">1221</a><td> this[CANCEL_HANDLER_SYMBOL](reason);<tr><td><a id="l1222"></a><a href="#l1222">1222</a><td> this[CANCEL_HANDLER_SYMBOL] = null;<tr><td><a id="l1223"></a><a href="#l1223">1223</a><td> }<tr><td><a id="l1224"></a><a href="#l1224">1224</a><td><tr><td><a id="l1225"></a><a href="#l1225">1225</a><td> if (this.state_ === PromiseState.BLOCKED) {<tr><td><a id="l1226"></a><a href="#l1226">1226</a><td> this.unblockAndResolve_(PromiseState.REJECTED, reason);<tr><td><a id="l1227"></a><a href="#l1227">1227</a><td> } else {<tr><td><a id="l1228"></a><a href="#l1228">1228</a><td> this.resolve_(PromiseState.REJECTED, reason);<tr><td><a id="l1229"></a><a href="#l1229">1229</a><td> }<tr><td><a id="l1230"></a><a href="#l1230">1230</a><td> }<tr><td><a id="l1231"></a><a href="#l1231">1231</a><td><tr><td><a id="l1232"></a><a href="#l1232">1232</a><td> function canCancel(promise) {<tr><td><a id="l1233"></a><a href="#l1233">1233</a><td> return promise.state_ === PromiseState.PENDING<tr><td><a id="l1234"></a><a href="#l1234">1234</a><td> || promise.state_ === PromiseState.BLOCKED;<tr><td><a id="l1235"></a><a href="#l1235">1235</a><td> }<tr><td><a id="l1236"></a><a href="#l1236">1236</a><td> },<tr><td><a id="l1237"></a><a href="#l1237">1237</a><td><tr><td><a id="l1238"></a><a href="#l1238">1238</a><td> /** @override */<tr><td><a id="l1239"></a><a href="#l1239">1239</a><td> isPending: function() {<tr><td><a id="l1240"></a><a href="#l1240">1240</a><td> return this.state_ === PromiseState.PENDING;<tr><td><a id="l1241"></a><a href="#l1241">1241</a><td> },<tr><td><a id="l1242"></a><a href="#l1242">1242</a><td><tr><td><a id="l1243"></a><a href="#l1243">1243</a><td> /** @override */<tr><td><a id="l1244"></a><a href="#l1244">1244</a><td> then: function(opt_callback, opt_errback) {<tr><td><a id="l1245"></a><a href="#l1245">1245</a><td> return this.addCallback_(<tr><td><a id="l1246"></a><a href="#l1246">1246</a><td> opt_callback, opt_errback, &#39;then&#39;, promise.Promise.prototype.then);<tr><td><a id="l1247"></a><a href="#l1247">1247</a><td> },<tr><td><a id="l1248"></a><a href="#l1248">1248</a><td><tr><td><a id="l1249"></a><a href="#l1249">1249</a><td> /** @override */<tr><td><a id="l1250"></a><a href="#l1250">1250</a><td> thenCatch: function(errback) {<tr><td><a id="l1251"></a><a href="#l1251">1251</a><td> return this.addCallback_(<tr><td><a id="l1252"></a><a href="#l1252">1252</a><td> null, errback, &#39;thenCatch&#39;, promise.Promise.prototype.thenCatch);<tr><td><a id="l1253"></a><a href="#l1253">1253</a><td> },<tr><td><a id="l1254"></a><a href="#l1254">1254</a><td><tr><td><a id="l1255"></a><a href="#l1255">1255</a><td> /** @override */<tr><td><a id="l1256"></a><a href="#l1256">1256</a><td> thenFinally: function(callback) {<tr><td><a id="l1257"></a><a href="#l1257">1257</a><td> var error;<tr><td><a id="l1258"></a><a href="#l1258">1258</a><td> var mustThrow = false;<tr><td><a id="l1259"></a><a href="#l1259">1259</a><td> return this.then(function() {<tr><td><a id="l1260"></a><a href="#l1260">1260</a><td> return callback();<tr><td><a id="l1261"></a><a href="#l1261">1261</a><td> }, function(err) {<tr><td><a id="l1262"></a><a href="#l1262">1262</a><td> error = err;<tr><td><a id="l1263"></a><a href="#l1263">1263</a><td> mustThrow = true;<tr><td><a id="l1264"></a><a href="#l1264">1264</a><td> return callback();<tr><td><a id="l1265"></a><a href="#l1265">1265</a><td> }).then(function() {<tr><td><a id="l1266"></a><a href="#l1266">1266</a><td> if (mustThrow) {<tr><td><a id="l1267"></a><a href="#l1267">1267</a><td> throw error;<tr><td><a id="l1268"></a><a href="#l1268">1268</a><td> }<tr><td><a id="l1269"></a><a href="#l1269">1269</a><td> });<tr><td><a id="l1270"></a><a href="#l1270">1270</a><td> },<tr><td><a id="l1271"></a><a href="#l1271">1271</a><td><tr><td><a id="l1272"></a><a href="#l1272">1272</a><td> /**<tr><td><a id="l1273"></a><a href="#l1273">1273</a><td> * Registers a new callback with this promise<tr><td><a id="l1274"></a><a href="#l1274">1274</a><td> * @param {(function(T): (R|IThenable&lt;R&gt;)|null|undefined)} callback The<tr><td><a id="l1275"></a><a href="#l1275">1275</a><td> * fulfillment callback.<tr><td><a id="l1276"></a><a href="#l1276">1276</a><td> * @param {(function(*): (R|IThenable&lt;R&gt;)|null|undefined)} errback The<tr><td><a id="l1277"></a><a href="#l1277">1277</a><td> * rejection callback.<tr><td><a id="l1278"></a><a href="#l1278">1278</a><td> * @param {string} name The callback name.<tr><td><a id="l1279"></a><a href="#l1279">1279</a><td> * @param {!Function} fn The function to use as the top of the stack when<tr><td><a id="l1280"></a><a href="#l1280">1280</a><td> * recording the callback&#39;s creation point.<tr><td><a id="l1281"></a><a href="#l1281">1281</a><td> * @return {!promise.Promise&lt;R&gt;} A new promise which will be resolved with the<tr><td><a id="l1282"></a><a href="#l1282">1282</a><td> * esult of the invoked callback.<tr><td><a id="l1283"></a><a href="#l1283">1283</a><td> * @template R<tr><td><a id="l1284"></a><a href="#l1284">1284</a><td> * @private<tr><td><a id="l1285"></a><a href="#l1285">1285</a><td> */<tr><td><a id="l1286"></a><a href="#l1286">1286</a><td> addCallback_: function(callback, errback, name, fn) {<tr><td><a id="l1287"></a><a href="#l1287">1287</a><td> if (!goog.isFunction(callback) &amp;&amp; !goog.isFunction(errback)) {<tr><td><a id="l1288"></a><a href="#l1288">1288</a><td> return this;<tr><td><a id="l1289"></a><a href="#l1289">1289</a><td> }<tr><td><a id="l1290"></a><a href="#l1290">1290</a><td><tr><td><a id="l1291"></a><a href="#l1291">1291</a><td> this.handled_ = true;<tr><td><a id="l1292"></a><a href="#l1292">1292</a><td> if (this.queue_) {<tr><td><a id="l1293"></a><a href="#l1293">1293</a><td> this.queue_.clearUnhandledRejection(this);<tr><td><a id="l1294"></a><a href="#l1294">1294</a><td> }<tr><td><a id="l1295"></a><a href="#l1295">1295</a><td><tr><td><a id="l1296"></a><a href="#l1296">1296</a><td> var cb = new Task(<tr><td><a id="l1297"></a><a href="#l1297">1297</a><td> this.flow_,<tr><td><a id="l1298"></a><a href="#l1298">1298</a><td> this.invokeCallback_.bind(this, callback, errback),<tr><td><a id="l1299"></a><a href="#l1299">1299</a><td> name,<tr><td><a id="l1300"></a><a href="#l1300">1300</a><td> promise.LONG_STACK_TRACES ? {name: &#39;Promise&#39;, top: fn} : undefined);<tr><td><a id="l1301"></a><a href="#l1301">1301</a><td> cb.promise.parent_ = this;<tr><td><a id="l1302"></a><a href="#l1302">1302</a><td><tr><td><a id="l1303"></a><a href="#l1303">1303</a><td> if (this.state_ !== PromiseState.PENDING &amp;&amp;<tr><td><a id="l1304"></a><a href="#l1304">1304</a><td> this.state_ !== PromiseState.BLOCKED) {<tr><td><a id="l1305"></a><a href="#l1305">1305</a><td> this.flow_.getActiveQueue_().enqueue(cb);<tr><td><a id="l1306"></a><a href="#l1306">1306</a><td> } else {<tr><td><a id="l1307"></a><a href="#l1307">1307</a><td> if (!this.callbacks_) {<tr><td><a id="l1308"></a><a href="#l1308">1308</a><td> this.callbacks_ = [];<tr><td><a id="l1309"></a><a href="#l1309">1309</a><td> }<tr><td><a id="l1310"></a><a href="#l1310">1310</a><td> this.callbacks_.push(cb);<tr><td><a id="l1311"></a><a href="#l1311">1311</a><td> cb.blocked = true;<tr><td><a id="l1312"></a><a href="#l1312">1312</a><td> this.flow_.getActiveQueue_().enqueue(cb);<tr><td><a id="l1313"></a><a href="#l1313">1313</a><td> }<tr><td><a id="l1314"></a><a href="#l1314">1314</a><td><tr><td><a id="l1315"></a><a href="#l1315">1315</a><td> return cb.promise;<tr><td><a id="l1316"></a><a href="#l1316">1316</a><td> },<tr><td><a id="l1317"></a><a href="#l1317">1317</a><td><tr><td><a id="l1318"></a><a href="#l1318">1318</a><td> /**<tr><td><a id="l1319"></a><a href="#l1319">1319</a><td> * Invokes a callback function attached to this promise.<tr><td><a id="l1320"></a><a href="#l1320">1320</a><td> * @param {(function(T): (R|IThenable&lt;R&gt;)|null|undefined)} callback The<tr><td><a id="l1321"></a><a href="#l1321">1321</a><td> * fulfillment callback.<tr><td><a id="l1322"></a><a href="#l1322">1322</a><td> * @param {(function(*): (R|IThenable&lt;R&gt;)|null|undefined)} errback The<tr><td><a id="l1323"></a><a href="#l1323">1323</a><td> * rejection callback.<tr><td><a id="l1324"></a><a href="#l1324">1324</a><td> * @template R<tr><td><a id="l1325"></a><a href="#l1325">1325</a><td> * @private<tr><td><a id="l1326"></a><a href="#l1326">1326</a><td> */<tr><td><a id="l1327"></a><a href="#l1327">1327</a><td> invokeCallback_: function(callback, errback) {<tr><td><a id="l1328"></a><a href="#l1328">1328</a><td> var callbackFn = callback;<tr><td><a id="l1329"></a><a href="#l1329">1329</a><td> if (this.state_ === PromiseState.REJECTED) {<tr><td><a id="l1330"></a><a href="#l1330">1330</a><td> callbackFn = errback;<tr><td><a id="l1331"></a><a href="#l1331">1331</a><td> }<tr><td><a id="l1332"></a><a href="#l1332">1332</a><td><tr><td><a id="l1333"></a><a href="#l1333">1333</a><td> if (goog.isFunction(callbackFn)) {<tr><td><a id="l1334"></a><a href="#l1334">1334</a><td> if (promise.isGenerator(callbackFn)) {<tr><td><a id="l1335"></a><a href="#l1335">1335</a><td> return promise.consume(callbackFn, null, this.value_);<tr><td><a id="l1336"></a><a href="#l1336">1336</a><td> }<tr><td><a id="l1337"></a><a href="#l1337">1337</a><td> return callbackFn(this.value_);<tr><td><a id="l1338"></a><a href="#l1338">1338</a><td> } else if (this.state_ === PromiseState.REJECTED) {<tr><td><a id="l1339"></a><a href="#l1339">1339</a><td> throw this.value_;<tr><td><a id="l1340"></a><a href="#l1340">1340</a><td> } else {<tr><td><a id="l1341"></a><a href="#l1341">1341</a><td> return this.value_;<tr><td><a id="l1342"></a><a href="#l1342">1342</a><td> }<tr><td><a id="l1343"></a><a href="#l1343">1343</a><td> }<tr><td><a id="l1344"></a><a href="#l1344">1344</a><td>});<tr><td><a id="l1345"></a><a href="#l1345">1345</a><td>promise.Thenable.addImplementation(promise.Promise);<tr><td><a id="l1346"></a><a href="#l1346">1346</a><td><tr><td><a id="l1347"></a><a href="#l1347">1347</a><td><tr><td><a id="l1348"></a><a href="#l1348">1348</a><td>/**<tr><td><a id="l1349"></a><a href="#l1349">1349</a><td> * Represents a value that will be resolved at some point in the future. This<tr><td><a id="l1350"></a><a href="#l1350">1350</a><td> * class represents the protected &quot;producer&quot; half of a Promise - each Deferred<tr><td><a id="l1351"></a><a href="#l1351">1351</a><td> * has a {@code promise} property that may be returned to consumers for<tr><td><a id="l1352"></a><a href="#l1352">1352</a><td> * registering callbacks, reserving the ability to resolve the deferred to the<tr><td><a id="l1353"></a><a href="#l1353">1353</a><td> * producer.<tr><td><a id="l1354"></a><a href="#l1354">1354</a><td> *<tr><td><a id="l1355"></a><a href="#l1355">1355</a><td> * If this Deferred is rejected and there are no listeners registered before<tr><td><a id="l1356"></a><a href="#l1356">1356</a><td> * the next turn of the event loop, the rejection will be passed to the<tr><td><a id="l1357"></a><a href="#l1357">1357</a><td> * {@link webdriver.promise.ControlFlow} as an unhandled failure.<tr><td><a id="l1358"></a><a href="#l1358">1358</a><td> *<tr><td><a id="l1359"></a><a href="#l1359">1359</a><td> * @implements {promise.Thenable&lt;T&gt;}<tr><td><a id="l1360"></a><a href="#l1360">1360</a><td> * @template T<tr><td><a id="l1361"></a><a href="#l1361">1361</a><td> */<tr><td><a id="l1362"></a><a href="#l1362">1362</a><td>promise.Deferred = goog.defineClass(null, {<tr><td><a id="l1363"></a><a href="#l1363">1363</a><td> /**<tr><td><a id="l1364"></a><a href="#l1364">1364</a><td> * @param {promise.ControlFlow=} opt_flow The control flow this instance was<tr><td><a id="l1365"></a><a href="#l1365">1365</a><td> * created under. This should only be provided during unit tests.<tr><td><a id="l1366"></a><a href="#l1366">1366</a><td> */<tr><td><a id="l1367"></a><a href="#l1367">1367</a><td> constructor: function(opt_flow) {<tr><td><a id="l1368"></a><a href="#l1368">1368</a><td> var fulfill, reject;<tr><td><a id="l1369"></a><a href="#l1369">1369</a><td><tr><td><a id="l1370"></a><a href="#l1370">1370</a><td> /** @type {!promise.Promise&lt;T&gt;} */<tr><td><a id="l1371"></a><a href="#l1371">1371</a><td> this.promise = new promise.Promise(function(f, r) {<tr><td><a id="l1372"></a><a href="#l1372">1372</a><td> fulfill = f;<tr><td><a id="l1373"></a><a href="#l1373">1373</a><td> reject = r;<tr><td><a id="l1374"></a><a href="#l1374">1374</a><td> }, opt_flow);<tr><td><a id="l1375"></a><a href="#l1375">1375</a><td><tr><td><a id="l1376"></a><a href="#l1376">1376</a><td> var self = this;<tr><td><a id="l1377"></a><a href="#l1377">1377</a><td> var checkNotSelf = function(value) {<tr><td><a id="l1378"></a><a href="#l1378">1378</a><td> if (value === self) {<tr><td><a id="l1379"></a><a href="#l1379">1379</a><td> throw new TypeError(&#39;May not resolve a Deferred with itself&#39;);<tr><td><a id="l1380"></a><a href="#l1380">1380</a><td> }<tr><td><a id="l1381"></a><a href="#l1381">1381</a><td> };<tr><td><a id="l1382"></a><a href="#l1382">1382</a><td><tr><td><a id="l1383"></a><a href="#l1383">1383</a><td> /**<tr><td><a id="l1384"></a><a href="#l1384">1384</a><td> * Resolves this deferred with the given value. It is safe to call this as a<tr><td><a id="l1385"></a><a href="#l1385">1385</a><td> * normal function (with no bound &quot;this&quot;).<tr><td><a id="l1386"></a><a href="#l1386">1386</a><td> * @param {(T|IThenable&lt;T&gt;|Thenable)=} opt_value The fulfilled value.<tr><td><a id="l1387"></a><a href="#l1387">1387</a><td> */<tr><td><a id="l1388"></a><a href="#l1388">1388</a><td> this.fulfill = function(opt_value) {<tr><td><a id="l1389"></a><a href="#l1389">1389</a><td> checkNotSelf(opt_value);<tr><td><a id="l1390"></a><a href="#l1390">1390</a><td> fulfill(opt_value);<tr><td><a id="l1391"></a><a href="#l1391">1391</a><td> };<tr><td><a id="l1392"></a><a href="#l1392">1392</a><td><tr><td><a id="l1393"></a><a href="#l1393">1393</a><td> /**<tr><td><a id="l1394"></a><a href="#l1394">1394</a><td> * Rejects this promise with the given reason. It is safe to call this as a<tr><td><a id="l1395"></a><a href="#l1395">1395</a><td> * normal function (with no bound &quot;this&quot;).<tr><td><a id="l1396"></a><a href="#l1396">1396</a><td> * @param {*=} opt_reason The rejection reason.<tr><td><a id="l1397"></a><a href="#l1397">1397</a><td> */<tr><td><a id="l1398"></a><a href="#l1398">1398</a><td> this.reject = function(opt_reason) {<tr><td><a id="l1399"></a><a href="#l1399">1399</a><td> checkNotSelf(opt_reason);<tr><td><a id="l1400"></a><a href="#l1400">1400</a><td> reject(opt_reason);<tr><td><a id="l1401"></a><a href="#l1401">1401</a><td> };<tr><td><a id="l1402"></a><a href="#l1402">1402</a><td> },<tr><td><a id="l1403"></a><a href="#l1403">1403</a><td><tr><td><a id="l1404"></a><a href="#l1404">1404</a><td> /** @override */<tr><td><a id="l1405"></a><a href="#l1405">1405</a><td> isPending: function() {<tr><td><a id="l1406"></a><a href="#l1406">1406</a><td> return this.promise.isPending();<tr><td><a id="l1407"></a><a href="#l1407">1407</a><td> },<tr><td><a id="l1408"></a><a href="#l1408">1408</a><td><tr><td><a id="l1409"></a><a href="#l1409">1409</a><td> /** @override */<tr><td><a id="l1410"></a><a href="#l1410">1410</a><td> cancel: function(opt_reason) {<tr><td><a id="l1411"></a><a href="#l1411">1411</a><td> this.promise.cancel(opt_reason);<tr><td><a id="l1412"></a><a href="#l1412">1412</a><td> },<tr><td><a id="l1413"></a><a href="#l1413">1413</a><td><tr><td><a id="l1414"></a><a href="#l1414">1414</a><td> /**<tr><td><a id="l1415"></a><a href="#l1415">1415</a><td> * @override<tr><td><a id="l1416"></a><a href="#l1416">1416</a><td> * @deprecated Use {@code then} from the promise property directly.<tr><td><a id="l1417"></a><a href="#l1417">1417</a><td> */<tr><td><a id="l1418"></a><a href="#l1418">1418</a><td> then: function(opt_cb, opt_eb) {<tr><td><a id="l1419"></a><a href="#l1419">1419</a><td> return this.promise.then(opt_cb, opt_eb);<tr><td><a id="l1420"></a><a href="#l1420">1420</a><td> },<tr><td><a id="l1421"></a><a href="#l1421">1421</a><td><tr><td><a id="l1422"></a><a href="#l1422">1422</a><td> /**<tr><td><a id="l1423"></a><a href="#l1423">1423</a><td> * @override<tr><td><a id="l1424"></a><a href="#l1424">1424</a><td> * @deprecated Use {@code thenCatch} from the promise property directly.<tr><td><a id="l1425"></a><a href="#l1425">1425</a><td> */<tr><td><a id="l1426"></a><a href="#l1426">1426</a><td> thenCatch: function(opt_eb) {<tr><td><a id="l1427"></a><a href="#l1427">1427</a><td> return this.promise.thenCatch(opt_eb);<tr><td><a id="l1428"></a><a href="#l1428">1428</a><td> },<tr><td><a id="l1429"></a><a href="#l1429">1429</a><td><tr><td><a id="l1430"></a><a href="#l1430">1430</a><td> /**<tr><td><a id="l1431"></a><a href="#l1431">1431</a><td> * @override<tr><td><a id="l1432"></a><a href="#l1432">1432</a><td> * @deprecated Use {@code thenFinally} from the promise property directly.<tr><td><a id="l1433"></a><a href="#l1433">1433</a><td> */<tr><td><a id="l1434"></a><a href="#l1434">1434</a><td> thenFinally: function(opt_cb) {<tr><td><a id="l1435"></a><a href="#l1435">1435</a><td> return this.promise.thenFinally(opt_cb);<tr><td><a id="l1436"></a><a href="#l1436">1436</a><td> }<tr><td><a id="l1437"></a><a href="#l1437">1437</a><td>});<tr><td><a id="l1438"></a><a href="#l1438">1438</a><td>promise.Thenable.addImplementation(promise.Deferred);<tr><td><a id="l1439"></a><a href="#l1439">1439</a><td><tr><td><a id="l1440"></a><a href="#l1440">1440</a><td><tr><td><a id="l1441"></a><a href="#l1441">1441</a><td>/**<tr><td><a id="l1442"></a><a href="#l1442">1442</a><td> * Tests if a value is an Error-like object. This is more than an straight<tr><td><a id="l1443"></a><a href="#l1443">1443</a><td> * instanceof check since the value may originate from another context.<tr><td><a id="l1444"></a><a href="#l1444">1444</a><td> * @param {*} value The value to test.<tr><td><a id="l1445"></a><a href="#l1445">1445</a><td> * @return {boolean} Whether the value is an error.<tr><td><a id="l1446"></a><a href="#l1446">1446</a><td> */<tr><td><a id="l1447"></a><a href="#l1447">1447</a><td>function isError(value) {<tr><td><a id="l1448"></a><a href="#l1448">1448</a><td> return value instanceof Error ||<tr><td><a id="l1449"></a><a href="#l1449">1449</a><td> goog.isObject(value) &amp;&amp;<tr><td><a id="l1450"></a><a href="#l1450">1450</a><td> (goog.isString(value.message) ||<tr><td><a id="l1451"></a><a href="#l1451">1451</a><td> // A special test for goog.testing.JsUnitException.<tr><td><a id="l1452"></a><a href="#l1452">1452</a><td> value.isJsUnitException);<tr><td><a id="l1453"></a><a href="#l1453">1453</a><td><tr><td><a id="l1454"></a><a href="#l1454">1454</a><td>}<tr><td><a id="l1455"></a><a href="#l1455">1455</a><td><tr><td><a id="l1456"></a><a href="#l1456">1456</a><td><tr><td><a id="l1457"></a><a href="#l1457">1457</a><td>/**<tr><td><a id="l1458"></a><a href="#l1458">1458</a><td> * Determines whether a {@code value} should be treated as a promise.<tr><td><a id="l1459"></a><a href="#l1459">1459</a><td> * Any object whose &quot;then&quot; property is a function will be considered a promise.<tr><td><a id="l1460"></a><a href="#l1460">1460</a><td> *<tr><td><a id="l1461"></a><a href="#l1461">1461</a><td> * @param {*} value The value to test.<tr><td><a id="l1462"></a><a href="#l1462">1462</a><td> * @return {boolean} Whether the value is a promise.<tr><td><a id="l1463"></a><a href="#l1463">1463</a><td> */<tr><td><a id="l1464"></a><a href="#l1464">1464</a><td>promise.isPromise = function(value) {<tr><td><a id="l1465"></a><a href="#l1465">1465</a><td> return !!value &amp;&amp; goog.isObject(value) &amp;&amp;<tr><td><a id="l1466"></a><a href="#l1466">1466</a><td> // Use array notation so the Closure compiler does not obfuscate away our<tr><td><a id="l1467"></a><a href="#l1467">1467</a><td> // contract. Use typeof rather than goog.isFunction because<tr><td><a id="l1468"></a><a href="#l1468">1468</a><td> // goog.isFunction accepts instanceof Function, which the promise spec<tr><td><a id="l1469"></a><a href="#l1469">1469</a><td> // does not.<tr><td><a id="l1470"></a><a href="#l1470">1470</a><td> typeof value[&#39;then&#39;] === &#39;function&#39;;<tr><td><a id="l1471"></a><a href="#l1471">1471</a><td>};<tr><td><a id="l1472"></a><a href="#l1472">1472</a><td><tr><td><a id="l1473"></a><a href="#l1473">1473</a><td><tr><td><a id="l1474"></a><a href="#l1474">1474</a><td>/**<tr><td><a id="l1475"></a><a href="#l1475">1475</a><td> * Creates a promise that will be resolved at a set time in the future.<tr><td><a id="l1476"></a><a href="#l1476">1476</a><td> * @param {number} ms The amount of time, in milliseconds, to wait before<tr><td><a id="l1477"></a><a href="#l1477">1477</a><td> * resolving the promise.<tr><td><a id="l1478"></a><a href="#l1478">1478</a><td> * @return {!promise.Promise} The promise.<tr><td><a id="l1479"></a><a href="#l1479">1479</a><td> */<tr><td><a id="l1480"></a><a href="#l1480">1480</a><td>promise.delayed = function(ms) {<tr><td><a id="l1481"></a><a href="#l1481">1481</a><td> var key;<tr><td><a id="l1482"></a><a href="#l1482">1482</a><td> return new promise.Promise(function(fulfill) {<tr><td><a id="l1483"></a><a href="#l1483">1483</a><td> key = setTimeout(function() {<tr><td><a id="l1484"></a><a href="#l1484">1484</a><td> key = null;<tr><td><a id="l1485"></a><a href="#l1485">1485</a><td> fulfill();<tr><td><a id="l1486"></a><a href="#l1486">1486</a><td> }, ms);<tr><td><a id="l1487"></a><a href="#l1487">1487</a><td> }).thenCatch(function(e) {<tr><td><a id="l1488"></a><a href="#l1488">1488</a><td> clearTimeout(key);<tr><td><a id="l1489"></a><a href="#l1489">1489</a><td> key = null;<tr><td><a id="l1490"></a><a href="#l1490">1490</a><td> throw e;<tr><td><a id="l1491"></a><a href="#l1491">1491</a><td> });<tr><td><a id="l1492"></a><a href="#l1492">1492</a><td>};<tr><td><a id="l1493"></a><a href="#l1493">1493</a><td><tr><td><a id="l1494"></a><a href="#l1494">1494</a><td><tr><td><a id="l1495"></a><a href="#l1495">1495</a><td>/**<tr><td><a id="l1496"></a><a href="#l1496">1496</a><td> * Creates a new deferred object.<tr><td><a id="l1497"></a><a href="#l1497">1497</a><td> * @return {!promise.Deferred&lt;T&gt;} The new deferred object.<tr><td><a id="l1498"></a><a href="#l1498">1498</a><td> * @template T<tr><td><a id="l1499"></a><a href="#l1499">1499</a><td> */<tr><td><a id="l1500"></a><a href="#l1500">1500</a><td>promise.defer = function() {<tr><td><a id="l1501"></a><a href="#l1501">1501</a><td> return new promise.Deferred();<tr><td><a id="l1502"></a><a href="#l1502">1502</a><td>};<tr><td><a id="l1503"></a><a href="#l1503">1503</a><td><tr><td><a id="l1504"></a><a href="#l1504">1504</a><td><tr><td><a id="l1505"></a><a href="#l1505">1505</a><td>/**<tr><td><a id="l1506"></a><a href="#l1506">1506</a><td> * Creates a promise that has been resolved with the given value.<tr><td><a id="l1507"></a><a href="#l1507">1507</a><td> * @param {T=} opt_value The resolved value.<tr><td><a id="l1508"></a><a href="#l1508">1508</a><td> * @return {!promise.Promise&lt;T&gt;} The resolved promise.<tr><td><a id="l1509"></a><a href="#l1509">1509</a><td> * @template T<tr><td><a id="l1510"></a><a href="#l1510">1510</a><td> */<tr><td><a id="l1511"></a><a href="#l1511">1511</a><td>promise.fulfilled = function(opt_value) {<tr><td><a id="l1512"></a><a href="#l1512">1512</a><td> if (opt_value instanceof promise.Promise) {<tr><td><a id="l1513"></a><a href="#l1513">1513</a><td> return opt_value;<tr><td><a id="l1514"></a><a href="#l1514">1514</a><td> }<tr><td><a id="l1515"></a><a href="#l1515">1515</a><td> return new promise.Promise(function(fulfill) {<tr><td><a id="l1516"></a><a href="#l1516">1516</a><td> fulfill(opt_value);<tr><td><a id="l1517"></a><a href="#l1517">1517</a><td> });<tr><td><a id="l1518"></a><a href="#l1518">1518</a><td>};<tr><td><a id="l1519"></a><a href="#l1519">1519</a><td><tr><td><a id="l1520"></a><a href="#l1520">1520</a><td><tr><td><a id="l1521"></a><a href="#l1521">1521</a><td>/**<tr><td><a id="l1522"></a><a href="#l1522">1522</a><td> * Creates a promise that has been rejected with the given reason.<tr><td><a id="l1523"></a><a href="#l1523">1523</a><td> * @param {*=} opt_reason The rejection reason; may be any value, but is<tr><td><a id="l1524"></a><a href="#l1524">1524</a><td> * usually an Error or a string.<tr><td><a id="l1525"></a><a href="#l1525">1525</a><td> * @return {!promise.Promise&lt;T&gt;} The rejected promise.<tr><td><a id="l1526"></a><a href="#l1526">1526</a><td> * @template T<tr><td><a id="l1527"></a><a href="#l1527">1527</a><td> */<tr><td><a id="l1528"></a><a href="#l1528">1528</a><td>promise.rejected = function(opt_reason) {<tr><td><a id="l1529"></a><a href="#l1529">1529</a><td> if (opt_reason instanceof promise.Promise) {<tr><td><a id="l1530"></a><a href="#l1530">1530</a><td> return opt_reason;<tr><td><a id="l1531"></a><a href="#l1531">1531</a><td> }<tr><td><a id="l1532"></a><a href="#l1532">1532</a><td> return new promise.Promise(function(_, reject) {<tr><td><a id="l1533"></a><a href="#l1533">1533</a><td> reject(opt_reason);<tr><td><a id="l1534"></a><a href="#l1534">1534</a><td> });<tr><td><a id="l1535"></a><a href="#l1535">1535</a><td>};<tr><td><a id="l1536"></a><a href="#l1536">1536</a><td><tr><td><a id="l1537"></a><a href="#l1537">1537</a><td><tr><td><a id="l1538"></a><a href="#l1538">1538</a><td>/**<tr><td><a id="l1539"></a><a href="#l1539">1539</a><td> * Wraps a function that expects a node-style callback as its final<tr><td><a id="l1540"></a><a href="#l1540">1540</a><td> * argument. This callback expects two arguments: an error value (which will be<tr><td><a id="l1541"></a><a href="#l1541">1541</a><td> * null if the call succeeded), and the success value as the second argument.<tr><td><a id="l1542"></a><a href="#l1542">1542</a><td> * The callback will the resolve or reject the returned promise, based on its arguments.<tr><td><a id="l1543"></a><a href="#l1543">1543</a><td> * @param {!Function} fn The function to wrap.<tr><td><a id="l1544"></a><a href="#l1544">1544</a><td> * @param {...?} var_args The arguments to apply to the function, excluding the<tr><td><a id="l1545"></a><a href="#l1545">1545</a><td> * final callback.<tr><td><a id="l1546"></a><a href="#l1546">1546</a><td> * @return {!promise.Promise} A promise that will be resolved with the<tr><td><a id="l1547"></a><a href="#l1547">1547</a><td> * result of the provided function&#39;s callback.<tr><td><a id="l1548"></a><a href="#l1548">1548</a><td> */<tr><td><a id="l1549"></a><a href="#l1549">1549</a><td>promise.checkedNodeCall = function(fn, var_args) {<tr><td><a id="l1550"></a><a href="#l1550">1550</a><td> var args = Arrays.slice(arguments, 1);<tr><td><a id="l1551"></a><a href="#l1551">1551</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1552"></a><a href="#l1552">1552</a><td> try {<tr><td><a id="l1553"></a><a href="#l1553">1553</a><td> args.push(function(error, value) {<tr><td><a id="l1554"></a><a href="#l1554">1554</a><td> error ? reject(error) : fulfill(value);<tr><td><a id="l1555"></a><a href="#l1555">1555</a><td> });<tr><td><a id="l1556"></a><a href="#l1556">1556</a><td> fn.apply(undefined, args);<tr><td><a id="l1557"></a><a href="#l1557">1557</a><td> } catch (ex) {<tr><td><a id="l1558"></a><a href="#l1558">1558</a><td> reject(ex);<tr><td><a id="l1559"></a><a href="#l1559">1559</a><td> }<tr><td><a id="l1560"></a><a href="#l1560">1560</a><td> });<tr><td><a id="l1561"></a><a href="#l1561">1561</a><td>};<tr><td><a id="l1562"></a><a href="#l1562">1562</a><td><tr><td><a id="l1563"></a><a href="#l1563">1563</a><td><tr><td><a id="l1564"></a><a href="#l1564">1564</a><td>/**<tr><td><a id="l1565"></a><a href="#l1565">1565</a><td> * Registers an observer on a promised {@code value}, returning a new promise<tr><td><a id="l1566"></a><a href="#l1566">1566</a><td> * that will be resolved when the value is. If {@code value} is not a promise,<tr><td><a id="l1567"></a><a href="#l1567">1567</a><td> * then the return promise will be immediately resolved.<tr><td><a id="l1568"></a><a href="#l1568">1568</a><td> * @param {*} value The value to observe.<tr><td><a id="l1569"></a><a href="#l1569">1569</a><td> * @param {Function=} opt_callback The function to call when the value is<tr><td><a id="l1570"></a><a href="#l1570">1570</a><td> * resolved successfully.<tr><td><a id="l1571"></a><a href="#l1571">1571</a><td> * @param {Function=} opt_errback The function to call when the value is<tr><td><a id="l1572"></a><a href="#l1572">1572</a><td> * rejected.<tr><td><a id="l1573"></a><a href="#l1573">1573</a><td> * @return {!promise.Promise} A new promise.<tr><td><a id="l1574"></a><a href="#l1574">1574</a><td> */<tr><td><a id="l1575"></a><a href="#l1575">1575</a><td>promise.when = function(value, opt_callback, opt_errback) {<tr><td><a id="l1576"></a><a href="#l1576">1576</a><td> if (promise.Thenable.isImplementation(value)) {<tr><td><a id="l1577"></a><a href="#l1577">1577</a><td> return value.then(opt_callback, opt_errback);<tr><td><a id="l1578"></a><a href="#l1578">1578</a><td> }<tr><td><a id="l1579"></a><a href="#l1579">1579</a><td><tr><td><a id="l1580"></a><a href="#l1580">1580</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1581"></a><a href="#l1581">1581</a><td> promise.asap(value, fulfill, reject);<tr><td><a id="l1582"></a><a href="#l1582">1582</a><td> }).then(opt_callback, opt_errback);<tr><td><a id="l1583"></a><a href="#l1583">1583</a><td>};<tr><td><a id="l1584"></a><a href="#l1584">1584</a><td><tr><td><a id="l1585"></a><a href="#l1585">1585</a><td><tr><td><a id="l1586"></a><a href="#l1586">1586</a><td>/**<tr><td><a id="l1587"></a><a href="#l1587">1587</a><td> * Invokes the appropriate callback function as soon as a promised<tr><td><a id="l1588"></a><a href="#l1588">1588</a><td> * {@code value} is resolved. This function is similar to<tr><td><a id="l1589"></a><a href="#l1589">1589</a><td> * {@link webdriver.promise.when}, except it does not return a new promise.<tr><td><a id="l1590"></a><a href="#l1590">1590</a><td> * @param {*} value The value to observe.<tr><td><a id="l1591"></a><a href="#l1591">1591</a><td> * @param {Function} callback The function to call when the value is<tr><td><a id="l1592"></a><a href="#l1592">1592</a><td> * resolved successfully.<tr><td><a id="l1593"></a><a href="#l1593">1593</a><td> * @param {Function=} opt_errback The function to call when the value is<tr><td><a id="l1594"></a><a href="#l1594">1594</a><td> * rejected.<tr><td><a id="l1595"></a><a href="#l1595">1595</a><td> */<tr><td><a id="l1596"></a><a href="#l1596">1596</a><td>promise.asap = function(value, callback, opt_errback) {<tr><td><a id="l1597"></a><a href="#l1597">1597</a><td> if (promise.isPromise(value)) {<tr><td><a id="l1598"></a><a href="#l1598">1598</a><td> value.then(callback, opt_errback);<tr><td><a id="l1599"></a><a href="#l1599">1599</a><td><tr><td><a id="l1600"></a><a href="#l1600">1600</a><td> // Maybe a Dojo-like deferred object?<tr><td><a id="l1601"></a><a href="#l1601">1601</a><td> } else if (!!value &amp;&amp; goog.isObject(value) &amp;&amp;<tr><td><a id="l1602"></a><a href="#l1602">1602</a><td> goog.isFunction(value.addCallbacks)) {<tr><td><a id="l1603"></a><a href="#l1603">1603</a><td> value.addCallbacks(callback, opt_errback);<tr><td><a id="l1604"></a><a href="#l1604">1604</a><td><tr><td><a id="l1605"></a><a href="#l1605">1605</a><td> // A raw value, return a resolved promise.<tr><td><a id="l1606"></a><a href="#l1606">1606</a><td> } else if (callback) {<tr><td><a id="l1607"></a><a href="#l1607">1607</a><td> callback(value);<tr><td><a id="l1608"></a><a href="#l1608">1608</a><td> }<tr><td><a id="l1609"></a><a href="#l1609">1609</a><td>};<tr><td><a id="l1610"></a><a href="#l1610">1610</a><td><tr><td><a id="l1611"></a><a href="#l1611">1611</a><td><tr><td><a id="l1612"></a><a href="#l1612">1612</a><td>/**<tr><td><a id="l1613"></a><a href="#l1613">1613</a><td> * Given an array of promises, will return a promise that will be fulfilled<tr><td><a id="l1614"></a><a href="#l1614">1614</a><td> * with the fulfillment values of the input array&#39;s values. If any of the<tr><td><a id="l1615"></a><a href="#l1615">1615</a><td> * input array&#39;s promises are rejected, the returned promise will be rejected<tr><td><a id="l1616"></a><a href="#l1616">1616</a><td> * with the same reason.<tr><td><a id="l1617"></a><a href="#l1617">1617</a><td> *<tr><td><a id="l1618"></a><a href="#l1618">1618</a><td> * @param {!Array&lt;(T|!promise.Promise&lt;T&gt;)&gt;} arr An array of<tr><td><a id="l1619"></a><a href="#l1619">1619</a><td> * promises to wait on.<tr><td><a id="l1620"></a><a href="#l1620">1620</a><td> * @return {!promise.Promise&lt;!Array&lt;T&gt;&gt;} A promise that is<tr><td><a id="l1621"></a><a href="#l1621">1621</a><td> * fulfilled with an array containing the fulfilled values of the<tr><td><a id="l1622"></a><a href="#l1622">1622</a><td> * input array, or rejected with the same reason as the first<tr><td><a id="l1623"></a><a href="#l1623">1623</a><td> * rejected value.<tr><td><a id="l1624"></a><a href="#l1624">1624</a><td> * @template T<tr><td><a id="l1625"></a><a href="#l1625">1625</a><td> */<tr><td><a id="l1626"></a><a href="#l1626">1626</a><td>promise.all = function(arr) {<tr><td><a id="l1627"></a><a href="#l1627">1627</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1628"></a><a href="#l1628">1628</a><td> var n = arr.length;<tr><td><a id="l1629"></a><a href="#l1629">1629</a><td> var values = [];<tr><td><a id="l1630"></a><a href="#l1630">1630</a><td><tr><td><a id="l1631"></a><a href="#l1631">1631</a><td> if (!n) {<tr><td><a id="l1632"></a><a href="#l1632">1632</a><td> fulfill(values);<tr><td><a id="l1633"></a><a href="#l1633">1633</a><td> return;<tr><td><a id="l1634"></a><a href="#l1634">1634</a><td> }<tr><td><a id="l1635"></a><a href="#l1635">1635</a><td><tr><td><a id="l1636"></a><a href="#l1636">1636</a><td> var toFulfill = n;<tr><td><a id="l1637"></a><a href="#l1637">1637</a><td> var onFulfilled = function(index, value) {<tr><td><a id="l1638"></a><a href="#l1638">1638</a><td> values[index] = value;<tr><td><a id="l1639"></a><a href="#l1639">1639</a><td> toFulfill--;<tr><td><a id="l1640"></a><a href="#l1640">1640</a><td> if (toFulfill == 0) {<tr><td><a id="l1641"></a><a href="#l1641">1641</a><td> fulfill(values);<tr><td><a id="l1642"></a><a href="#l1642">1642</a><td> }<tr><td><a id="l1643"></a><a href="#l1643">1643</a><td> };<tr><td><a id="l1644"></a><a href="#l1644">1644</a><td><tr><td><a id="l1645"></a><a href="#l1645">1645</a><td> for (var i = 0; i &lt; n; ++i) {<tr><td><a id="l1646"></a><a href="#l1646">1646</a><td> promise.asap(arr[i], goog.partial(onFulfilled, i), reject);<tr><td><a id="l1647"></a><a href="#l1647">1647</a><td> }<tr><td><a id="l1648"></a><a href="#l1648">1648</a><td> });<tr><td><a id="l1649"></a><a href="#l1649">1649</a><td>};<tr><td><a id="l1650"></a><a href="#l1650">1650</a><td><tr><td><a id="l1651"></a><a href="#l1651">1651</a><td><tr><td><a id="l1652"></a><a href="#l1652">1652</a><td>/**<tr><td><a id="l1653"></a><a href="#l1653">1653</a><td> * Calls a function for each element in an array and inserts the result into a<tr><td><a id="l1654"></a><a href="#l1654">1654</a><td> * new array, which is used as the fulfillment value of the promise returned<tr><td><a id="l1655"></a><a href="#l1655">1655</a><td> * by this function.<tr><td><a id="l1656"></a><a href="#l1656">1656</a><td> *<tr><td><a id="l1657"></a><a href="#l1657">1657</a><td> * If the return value of the mapping function is a promise, this function<tr><td><a id="l1658"></a><a href="#l1658">1658</a><td> * will wait for it to be fulfilled before inserting it into the new array.<tr><td><a id="l1659"></a><a href="#l1659">1659</a><td> *<tr><td><a id="l1660"></a><a href="#l1660">1660</a><td> * If the mapping function throws or returns a rejected promise, the<tr><td><a id="l1661"></a><a href="#l1661">1661</a><td> * promise returned by this function will be rejected with the same reason.<tr><td><a id="l1662"></a><a href="#l1662">1662</a><td> * Only the first failure will be reported; all subsequent errors will be<tr><td><a id="l1663"></a><a href="#l1663">1663</a><td> * silently ignored.<tr><td><a id="l1664"></a><a href="#l1664">1664</a><td> *<tr><td><a id="l1665"></a><a href="#l1665">1665</a><td> * @param {!(Array&lt;TYPE&gt;|promise.Promise&lt;!Array&lt;TYPE&gt;&gt;)} arr The<tr><td><a id="l1666"></a><a href="#l1666">1666</a><td> * array to iterator over, or a promise that will resolve to said array.<tr><td><a id="l1667"></a><a href="#l1667">1667</a><td> * @param {function(this: SELF, TYPE, number, !Array&lt;TYPE&gt;): ?} fn The<tr><td><a id="l1668"></a><a href="#l1668">1668</a><td> * function to call for each element in the array. This function should<tr><td><a id="l1669"></a><a href="#l1669">1669</a><td> * expect three arguments (the element, the index, and the array itself.<tr><td><a id="l1670"></a><a href="#l1670">1670</a><td> * @param {SELF=} opt_self The object to be used as the value of &#39;this&#39; within<tr><td><a id="l1671"></a><a href="#l1671">1671</a><td> * {@code fn}.<tr><td><a id="l1672"></a><a href="#l1672">1672</a><td> * @template TYPE, SELF<tr><td><a id="l1673"></a><a href="#l1673">1673</a><td> */<tr><td><a id="l1674"></a><a href="#l1674">1674</a><td>promise.map = function(arr, fn, opt_self) {<tr><td><a id="l1675"></a><a href="#l1675">1675</a><td> return promise.fulfilled(arr).then(function(v) {<tr><td><a id="l1676"></a><a href="#l1676">1676</a><td> goog.asserts.assertNumber(v.length, &#39;not an array like value&#39;);<tr><td><a id="l1677"></a><a href="#l1677">1677</a><td> var arr = /** @type {!Array} */(v);<tr><td><a id="l1678"></a><a href="#l1678">1678</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1679"></a><a href="#l1679">1679</a><td> var n = arr.length;<tr><td><a id="l1680"></a><a href="#l1680">1680</a><td> var values = new Array(n);<tr><td><a id="l1681"></a><a href="#l1681">1681</a><td> (function processNext(i) {<tr><td><a id="l1682"></a><a href="#l1682">1682</a><td> for (; i &lt; n; i++) {<tr><td><a id="l1683"></a><a href="#l1683">1683</a><td> if (i in arr) {<tr><td><a id="l1684"></a><a href="#l1684">1684</a><td> break;<tr><td><a id="l1685"></a><a href="#l1685">1685</a><td> }<tr><td><a id="l1686"></a><a href="#l1686">1686</a><td> }<tr><td><a id="l1687"></a><a href="#l1687">1687</a><td> if (i &gt;= n) {<tr><td><a id="l1688"></a><a href="#l1688">1688</a><td> fulfill(values);<tr><td><a id="l1689"></a><a href="#l1689">1689</a><td> return;<tr><td><a id="l1690"></a><a href="#l1690">1690</a><td> }<tr><td><a id="l1691"></a><a href="#l1691">1691</a><td> try {<tr><td><a id="l1692"></a><a href="#l1692">1692</a><td> promise.asap(<tr><td><a id="l1693"></a><a href="#l1693">1693</a><td> fn.call(opt_self, arr[i], i, /** @type {!Array} */(arr)),<tr><td><a id="l1694"></a><a href="#l1694">1694</a><td> function(value) {<tr><td><a id="l1695"></a><a href="#l1695">1695</a><td> values[i] = value;<tr><td><a id="l1696"></a><a href="#l1696">1696</a><td> processNext(i + 1);<tr><td><a id="l1697"></a><a href="#l1697">1697</a><td> },<tr><td><a id="l1698"></a><a href="#l1698">1698</a><td> reject);<tr><td><a id="l1699"></a><a href="#l1699">1699</a><td> } catch (ex) {<tr><td><a id="l1700"></a><a href="#l1700">1700</a><td> reject(ex);<tr><td><a id="l1701"></a><a href="#l1701">1701</a><td> }<tr><td><a id="l1702"></a><a href="#l1702">1702</a><td> })(0);<tr><td><a id="l1703"></a><a href="#l1703">1703</a><td> });<tr><td><a id="l1704"></a><a href="#l1704">1704</a><td> });<tr><td><a id="l1705"></a><a href="#l1705">1705</a><td>};<tr><td><a id="l1706"></a><a href="#l1706">1706</a><td><tr><td><a id="l1707"></a><a href="#l1707">1707</a><td><tr><td><a id="l1708"></a><a href="#l1708">1708</a><td>/**<tr><td><a id="l1709"></a><a href="#l1709">1709</a><td> * Calls a function for each element in an array, and if the function returns<tr><td><a id="l1710"></a><a href="#l1710">1710</a><td> * true adds the element to a new array.<tr><td><a id="l1711"></a><a href="#l1711">1711</a><td> *<tr><td><a id="l1712"></a><a href="#l1712">1712</a><td> * If the return value of the filter function is a promise, this function<tr><td><a id="l1713"></a><a href="#l1713">1713</a><td> * will wait for it to be fulfilled before determining whether to insert the<tr><td><a id="l1714"></a><a href="#l1714">1714</a><td> * element into the new array.<tr><td><a id="l1715"></a><a href="#l1715">1715</a><td> *<tr><td><a id="l1716"></a><a href="#l1716">1716</a><td> * If the filter function throws or returns a rejected promise, the promise<tr><td><a id="l1717"></a><a href="#l1717">1717</a><td> * returned by this function will be rejected with the same reason. Only the<tr><td><a id="l1718"></a><a href="#l1718">1718</a><td> * first failure will be reported; all subsequent errors will be silently<tr><td><a id="l1719"></a><a href="#l1719">1719</a><td> * ignored.<tr><td><a id="l1720"></a><a href="#l1720">1720</a><td> *<tr><td><a id="l1721"></a><a href="#l1721">1721</a><td> * @param {!(Array&lt;TYPE&gt;|promise.Promise&lt;!Array&lt;TYPE&gt;&gt;)} arr The<tr><td><a id="l1722"></a><a href="#l1722">1722</a><td> * array to iterator over, or a promise that will resolve to said array.<tr><td><a id="l1723"></a><a href="#l1723">1723</a><td> * @param {function(this: SELF, TYPE, number, !Array&lt;TYPE&gt;): (<tr><td><a id="l1724"></a><a href="#l1724">1724</a><td> * boolean|promise.Promise&lt;boolean&gt;)} fn The function<tr><td><a id="l1725"></a><a href="#l1725">1725</a><td> * to call for each element in the array.<tr><td><a id="l1726"></a><a href="#l1726">1726</a><td> * @param {SELF=} opt_self The object to be used as the value of &#39;this&#39; within<tr><td><a id="l1727"></a><a href="#l1727">1727</a><td> * {@code fn}.<tr><td><a id="l1728"></a><a href="#l1728">1728</a><td> * @template TYPE, SELF<tr><td><a id="l1729"></a><a href="#l1729">1729</a><td> */<tr><td><a id="l1730"></a><a href="#l1730">1730</a><td>promise.filter = function(arr, fn, opt_self) {<tr><td><a id="l1731"></a><a href="#l1731">1731</a><td> return promise.fulfilled(arr).then(function(v) {<tr><td><a id="l1732"></a><a href="#l1732">1732</a><td> goog.asserts.assertNumber(v.length, &#39;not an array like value&#39;);<tr><td><a id="l1733"></a><a href="#l1733">1733</a><td> var arr = /** @type {!Array} */(v);<tr><td><a id="l1734"></a><a href="#l1734">1734</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1735"></a><a href="#l1735">1735</a><td> var n = arr.length;<tr><td><a id="l1736"></a><a href="#l1736">1736</a><td> var values = [];<tr><td><a id="l1737"></a><a href="#l1737">1737</a><td> var valuesLength = 0;<tr><td><a id="l1738"></a><a href="#l1738">1738</a><td> (function processNext(i) {<tr><td><a id="l1739"></a><a href="#l1739">1739</a><td> for (; i &lt; n; i++) {<tr><td><a id="l1740"></a><a href="#l1740">1740</a><td> if (i in arr) {<tr><td><a id="l1741"></a><a href="#l1741">1741</a><td> break;<tr><td><a id="l1742"></a><a href="#l1742">1742</a><td> }<tr><td><a id="l1743"></a><a href="#l1743">1743</a><td> }<tr><td><a id="l1744"></a><a href="#l1744">1744</a><td> if (i &gt;= n) {<tr><td><a id="l1745"></a><a href="#l1745">1745</a><td> fulfill(values);<tr><td><a id="l1746"></a><a href="#l1746">1746</a><td> return;<tr><td><a id="l1747"></a><a href="#l1747">1747</a><td> }<tr><td><a id="l1748"></a><a href="#l1748">1748</a><td> try {<tr><td><a id="l1749"></a><a href="#l1749">1749</a><td> var value = arr[i];<tr><td><a id="l1750"></a><a href="#l1750">1750</a><td> var include = fn.call(opt_self, value, i, /** @type {!Array} */(arr));<tr><td><a id="l1751"></a><a href="#l1751">1751</a><td> promise.asap(include, function(include) {<tr><td><a id="l1752"></a><a href="#l1752">1752</a><td> if (include) {<tr><td><a id="l1753"></a><a href="#l1753">1753</a><td> values[valuesLength++] = value;<tr><td><a id="l1754"></a><a href="#l1754">1754</a><td> }<tr><td><a id="l1755"></a><a href="#l1755">1755</a><td> processNext(i + 1);<tr><td><a id="l1756"></a><a href="#l1756">1756</a><td> }, reject);<tr><td><a id="l1757"></a><a href="#l1757">1757</a><td> } catch (ex) {<tr><td><a id="l1758"></a><a href="#l1758">1758</a><td> reject(ex);<tr><td><a id="l1759"></a><a href="#l1759">1759</a><td> }<tr><td><a id="l1760"></a><a href="#l1760">1760</a><td> })(0);<tr><td><a id="l1761"></a><a href="#l1761">1761</a><td> });<tr><td><a id="l1762"></a><a href="#l1762">1762</a><td> });<tr><td><a id="l1763"></a><a href="#l1763">1763</a><td>};<tr><td><a id="l1764"></a><a href="#l1764">1764</a><td><tr><td><a id="l1765"></a><a href="#l1765">1765</a><td><tr><td><a id="l1766"></a><a href="#l1766">1766</a><td>/**<tr><td><a id="l1767"></a><a href="#l1767">1767</a><td> * Returns a promise that will be resolved with the input value in a<tr><td><a id="l1768"></a><a href="#l1768">1768</a><td> * fully-resolved state. If the value is an array, each element will be fully<tr><td><a id="l1769"></a><a href="#l1769">1769</a><td> * resolved. Likewise, if the value is an object, all keys will be fully<tr><td><a id="l1770"></a><a href="#l1770">1770</a><td> * resolved. In both cases, all nested arrays and objects will also be<tr><td><a id="l1771"></a><a href="#l1771">1771</a><td> * fully resolved. All fields are resolved in place; the returned promise will<tr><td><a id="l1772"></a><a href="#l1772">1772</a><td> * resolve on {@code value} and not a copy.<tr><td><a id="l1773"></a><a href="#l1773">1773</a><td> *<tr><td><a id="l1774"></a><a href="#l1774">1774</a><td> * Warning: This function makes no checks against objects that contain<tr><td><a id="l1775"></a><a href="#l1775">1775</a><td> * cyclical references:<tr><td><a id="l1776"></a><a href="#l1776">1776</a><td> *<tr><td><a id="l1777"></a><a href="#l1777">1777</a><td> * var value = {};<tr><td><a id="l1778"></a><a href="#l1778">1778</a><td> * value[&#39;self&#39;] = value;<tr><td><a id="l1779"></a><a href="#l1779">1779</a><td> * promise.fullyResolved(value); // Stack overflow.<tr><td><a id="l1780"></a><a href="#l1780">1780</a><td> *<tr><td><a id="l1781"></a><a href="#l1781">1781</a><td> * @param {*} value The value to fully resolve.<tr><td><a id="l1782"></a><a href="#l1782">1782</a><td> * @return {!promise.Promise} A promise for a fully resolved version<tr><td><a id="l1783"></a><a href="#l1783">1783</a><td> * of the input value.<tr><td><a id="l1784"></a><a href="#l1784">1784</a><td> */<tr><td><a id="l1785"></a><a href="#l1785">1785</a><td>promise.fullyResolved = function(value) {<tr><td><a id="l1786"></a><a href="#l1786">1786</a><td> if (promise.isPromise(value)) {<tr><td><a id="l1787"></a><a href="#l1787">1787</a><td> return promise.when(value, fullyResolveValue);<tr><td><a id="l1788"></a><a href="#l1788">1788</a><td> }<tr><td><a id="l1789"></a><a href="#l1789">1789</a><td> return fullyResolveValue(value);<tr><td><a id="l1790"></a><a href="#l1790">1790</a><td>};<tr><td><a id="l1791"></a><a href="#l1791">1791</a><td><tr><td><a id="l1792"></a><a href="#l1792">1792</a><td><tr><td><a id="l1793"></a><a href="#l1793">1793</a><td>/**<tr><td><a id="l1794"></a><a href="#l1794">1794</a><td> * @param {*} value The value to fully resolve. If a promise, assumed to<tr><td><a id="l1795"></a><a href="#l1795">1795</a><td> * already be resolved.<tr><td><a id="l1796"></a><a href="#l1796">1796</a><td> * @return {!promise.Promise} A promise for a fully resolved version<tr><td><a id="l1797"></a><a href="#l1797">1797</a><td> * of the input value.<tr><td><a id="l1798"></a><a href="#l1798">1798</a><td> */<tr><td><a id="l1799"></a><a href="#l1799">1799</a><td> function fullyResolveValue(value) {<tr><td><a id="l1800"></a><a href="#l1800">1800</a><td> switch (goog.typeOf(value)) {<tr><td><a id="l1801"></a><a href="#l1801">1801</a><td> case &#39;array&#39;:<tr><td><a id="l1802"></a><a href="#l1802">1802</a><td> return fullyResolveKeys(/** @type {!Array} */ (value));<tr><td><a id="l1803"></a><a href="#l1803">1803</a><td><tr><td><a id="l1804"></a><a href="#l1804">1804</a><td> case &#39;object&#39;:<tr><td><a id="l1805"></a><a href="#l1805">1805</a><td> if (promise.isPromise(value)) {<tr><td><a id="l1806"></a><a href="#l1806">1806</a><td> // We get here when the original input value is a promise that<tr><td><a id="l1807"></a><a href="#l1807">1807</a><td> // resolves to itself. When the user provides us with such a promise,<tr><td><a id="l1808"></a><a href="#l1808">1808</a><td> // trust that it counts as a &quot;fully resolved&quot; value and return it.<tr><td><a id="l1809"></a><a href="#l1809">1809</a><td> // Of course, since it&#39;s already a promise, we can just return it<tr><td><a id="l1810"></a><a href="#l1810">1810</a><td> // to the user instead of wrapping it in another promise.<tr><td><a id="l1811"></a><a href="#l1811">1811</a><td> return /** @type {!promise.Promise} */ (value);<tr><td><a id="l1812"></a><a href="#l1812">1812</a><td> }<tr><td><a id="l1813"></a><a href="#l1813">1813</a><td><tr><td><a id="l1814"></a><a href="#l1814">1814</a><td> if (goog.isNumber(value.nodeType) &amp;&amp;<tr><td><a id="l1815"></a><a href="#l1815">1815</a><td> goog.isObject(value.ownerDocument) &amp;&amp;<tr><td><a id="l1816"></a><a href="#l1816">1816</a><td> goog.isNumber(value.ownerDocument.nodeType)) {<tr><td><a id="l1817"></a><a href="#l1817">1817</a><td> // DOM node; return early to avoid infinite recursion. Should we<tr><td><a id="l1818"></a><a href="#l1818">1818</a><td> // only support objects with a certain level of nesting?<tr><td><a id="l1819"></a><a href="#l1819">1819</a><td> return promise.fulfilled(value);<tr><td><a id="l1820"></a><a href="#l1820">1820</a><td> }<tr><td><a id="l1821"></a><a href="#l1821">1821</a><td><tr><td><a id="l1822"></a><a href="#l1822">1822</a><td> return fullyResolveKeys(/** @type {!Object} */ (value));<tr><td><a id="l1823"></a><a href="#l1823">1823</a><td><tr><td><a id="l1824"></a><a href="#l1824">1824</a><td> default: // boolean, function, null, number, string, undefined<tr><td><a id="l1825"></a><a href="#l1825">1825</a><td> return promise.fulfilled(value);<tr><td><a id="l1826"></a><a href="#l1826">1826</a><td> }<tr><td><a id="l1827"></a><a href="#l1827">1827</a><td>}<tr><td><a id="l1828"></a><a href="#l1828">1828</a><td><tr><td><a id="l1829"></a><a href="#l1829">1829</a><td><tr><td><a id="l1830"></a><a href="#l1830">1830</a><td>/**<tr><td><a id="l1831"></a><a href="#l1831">1831</a><td> * @param {!(Array|Object)} obj the object to resolve.<tr><td><a id="l1832"></a><a href="#l1832">1832</a><td> * @return {!promise.Promise} A promise that will be resolved with the<tr><td><a id="l1833"></a><a href="#l1833">1833</a><td> * input object once all of its values have been fully resolved.<tr><td><a id="l1834"></a><a href="#l1834">1834</a><td> */<tr><td><a id="l1835"></a><a href="#l1835">1835</a><td> function fullyResolveKeys(obj) {<tr><td><a id="l1836"></a><a href="#l1836">1836</a><td> var isArray = goog.isArray(obj);<tr><td><a id="l1837"></a><a href="#l1837">1837</a><td> var numKeys = isArray ? obj.length : Objects.getCount(obj);<tr><td><a id="l1838"></a><a href="#l1838">1838</a><td> if (!numKeys) {<tr><td><a id="l1839"></a><a href="#l1839">1839</a><td> return promise.fulfilled(obj);<tr><td><a id="l1840"></a><a href="#l1840">1840</a><td> }<tr><td><a id="l1841"></a><a href="#l1841">1841</a><td><tr><td><a id="l1842"></a><a href="#l1842">1842</a><td> var numResolved = 0;<tr><td><a id="l1843"></a><a href="#l1843">1843</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l1844"></a><a href="#l1844">1844</a><td> // In pre-IE9, goog.array.forEach will not iterate properly over arrays<tr><td><a id="l1845"></a><a href="#l1845">1845</a><td> // containing undefined values because &quot;index in array&quot; returns false<tr><td><a id="l1846"></a><a href="#l1846">1846</a><td> // when array[index] === undefined (even for x = [undefined, 1]). To get<tr><td><a id="l1847"></a><a href="#l1847">1847</a><td> // around this, we need to use our own forEach implementation.<tr><td><a id="l1848"></a><a href="#l1848">1848</a><td> // DO NOT REMOVE THIS UNTIL WE NO LONGER SUPPORT IE8. This cannot be<tr><td><a id="l1849"></a><a href="#l1849">1849</a><td> // reproduced in IE9 by changing the browser/document modes, it requires an<tr><td><a id="l1850"></a><a href="#l1850">1850</a><td> // actual pre-IE9 browser. Yay, IE!<tr><td><a id="l1851"></a><a href="#l1851">1851</a><td> var forEachKey = !isArray ? Objects.forEach : function(arr, fn) {<tr><td><a id="l1852"></a><a href="#l1852">1852</a><td> var n = arr.length;<tr><td><a id="l1853"></a><a href="#l1853">1853</a><td> for (var i = 0; i &lt; n; ++i) {<tr><td><a id="l1854"></a><a href="#l1854">1854</a><td> fn.call(null, arr[i], i, arr);<tr><td><a id="l1855"></a><a href="#l1855">1855</a><td> }<tr><td><a id="l1856"></a><a href="#l1856">1856</a><td> };<tr><td><a id="l1857"></a><a href="#l1857">1857</a><td><tr><td><a id="l1858"></a><a href="#l1858">1858</a><td> forEachKey(obj, function(partialValue, key) {<tr><td><a id="l1859"></a><a href="#l1859">1859</a><td> var type = goog.typeOf(partialValue);<tr><td><a id="l1860"></a><a href="#l1860">1860</a><td> if (type != &#39;array&#39; &amp;&amp; type != &#39;object&#39;) {<tr><td><a id="l1861"></a><a href="#l1861">1861</a><td> maybeResolveValue();<tr><td><a id="l1862"></a><a href="#l1862">1862</a><td> return;<tr><td><a id="l1863"></a><a href="#l1863">1863</a><td> }<tr><td><a id="l1864"></a><a href="#l1864">1864</a><td><tr><td><a id="l1865"></a><a href="#l1865">1865</a><td> promise.fullyResolved(partialValue).then(<tr><td><a id="l1866"></a><a href="#l1866">1866</a><td> function(resolvedValue) {<tr><td><a id="l1867"></a><a href="#l1867">1867</a><td> obj[key] = resolvedValue;<tr><td><a id="l1868"></a><a href="#l1868">1868</a><td> maybeResolveValue();<tr><td><a id="l1869"></a><a href="#l1869">1869</a><td> },<tr><td><a id="l1870"></a><a href="#l1870">1870</a><td> reject);<tr><td><a id="l1871"></a><a href="#l1871">1871</a><td> });<tr><td><a id="l1872"></a><a href="#l1872">1872</a><td><tr><td><a id="l1873"></a><a href="#l1873">1873</a><td> function maybeResolveValue() {<tr><td><a id="l1874"></a><a href="#l1874">1874</a><td> if (++numResolved == numKeys) {<tr><td><a id="l1875"></a><a href="#l1875">1875</a><td> fulfill(obj);<tr><td><a id="l1876"></a><a href="#l1876">1876</a><td> }<tr><td><a id="l1877"></a><a href="#l1877">1877</a><td> }<tr><td><a id="l1878"></a><a href="#l1878">1878</a><td> });<tr><td><a id="l1879"></a><a href="#l1879">1879</a><td>}<tr><td><a id="l1880"></a><a href="#l1880">1880</a><td><tr><td><a id="l1881"></a><a href="#l1881">1881</a><td><tr><td><a id="l1882"></a><a href="#l1882">1882</a><td>//////////////////////////////////////////////////////////////////////////////<tr><td><a id="l1883"></a><a href="#l1883">1883</a><td>//<tr><td><a id="l1884"></a><a href="#l1884">1884</a><td>// promise.ControlFlow<tr><td><a id="l1885"></a><a href="#l1885">1885</a><td>//<tr><td><a id="l1886"></a><a href="#l1886">1886</a><td>//////////////////////////////////////////////////////////////////////////////<tr><td><a id="l1887"></a><a href="#l1887">1887</a><td><tr><td><a id="l1888"></a><a href="#l1888">1888</a><td><tr><td><a id="l1889"></a><a href="#l1889">1889</a><td><tr><td><a id="l1890"></a><a href="#l1890">1890</a><td>/**<tr><td><a id="l1891"></a><a href="#l1891">1891</a><td> * Handles the execution of scheduled tasks, each of which may be an<tr><td><a id="l1892"></a><a href="#l1892">1892</a><td> * asynchronous operation. The control flow will ensure tasks are executed in<tr><td><a id="l1893"></a><a href="#l1893">1893</a><td> * the ordered scheduled, starting each task only once those before it have<tr><td><a id="l1894"></a><a href="#l1894">1894</a><td> * completed.<tr><td><a id="l1895"></a><a href="#l1895">1895</a><td> *<tr><td><a id="l1896"></a><a href="#l1896">1896</a><td> * Each task scheduled within this flow may return a<tr><td><a id="l1897"></a><a href="#l1897">1897</a><td> * {@link webdriver.promise.Promise} to indicate it is an asynchronous<tr><td><a id="l1898"></a><a href="#l1898">1898</a><td> * operation. The ControlFlow will wait for such promises to be resolved before<tr><td><a id="l1899"></a><a href="#l1899">1899</a><td> * marking the task as completed.<tr><td><a id="l1900"></a><a href="#l1900">1900</a><td> *<tr><td><a id="l1901"></a><a href="#l1901">1901</a><td> * Tasks and each callback registered on a {@link webdriver.promise.Promise}<tr><td><a id="l1902"></a><a href="#l1902">1902</a><td> * will be run in their own ControlFlow frame. Any tasks scheduled within a<tr><td><a id="l1903"></a><a href="#l1903">1903</a><td> * frame will take priority over previously scheduled tasks. Furthermore, if any<tr><td><a id="l1904"></a><a href="#l1904">1904</a><td> * of the tasks in the frame fail, the remainder of the tasks in that frame will<tr><td><a id="l1905"></a><a href="#l1905">1905</a><td> * be discarded and the failure will be propagated to the user through the<tr><td><a id="l1906"></a><a href="#l1906">1906</a><td> * callback/task&#39;s promised result.<tr><td><a id="l1907"></a><a href="#l1907">1907</a><td> *<tr><td><a id="l1908"></a><a href="#l1908">1908</a><td> * Each time a ControlFlow empties its task queue, it will fire an<tr><td><a id="l1909"></a><a href="#l1909">1909</a><td> * {@link webdriver.promise.ControlFlow.EventType.IDLE IDLE} event. Conversely,<tr><td><a id="l1910"></a><a href="#l1910">1910</a><td> * whenever the flow terminates due to an unhandled error, it will remove all<tr><td><a id="l1911"></a><a href="#l1911">1911</a><td> * remaining tasks in its queue and fire an<tr><td><a id="l1912"></a><a href="#l1912">1912</a><td> * {@link webdriver.promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION<tr><td><a id="l1913"></a><a href="#l1913">1913</a><td> * UNCAUGHT_EXCEPTION} event. If there are no listeners registered with the<tr><td><a id="l1914"></a><a href="#l1914">1914</a><td> * flow, the error will be rethrown to the global error handler.<tr><td><a id="l1915"></a><a href="#l1915">1915</a><td> *<tr><td><a id="l1916"></a><a href="#l1916">1916</a><td> * Refer to the {@link webdriver.promise} module documentation for a detailed<tr><td><a id="l1917"></a><a href="#l1917">1917</a><td> * explanation of how the ControlFlow coordinates task execution.<tr><td><a id="l1918"></a><a href="#l1918">1918</a><td> *<tr><td><a id="l1919"></a><a href="#l1919">1919</a><td> * @final<tr><td><a id="l1920"></a><a href="#l1920">1920</a><td> */<tr><td><a id="l1921"></a><a href="#l1921">1921</a><td>promise.ControlFlow = goog.defineClass(EventEmitter, {<tr><td><a id="l1922"></a><a href="#l1922">1922</a><td> // TODO: remove this empty comment when the compiler properly handles<tr><td><a id="l1923"></a><a href="#l1923">1923</a><td> // goog.defineClass with a missing constructor comment.<tr><td><a id="l1924"></a><a href="#l1924">1924</a><td> /** @constructor */<tr><td><a id="l1925"></a><a href="#l1925">1925</a><td> constructor: function() {<tr><td><a id="l1926"></a><a href="#l1926">1926</a><td> promise.ControlFlow.base(this, &#39;constructor&#39;);<tr><td><a id="l1927"></a><a href="#l1927">1927</a><td><tr><td><a id="l1928"></a><a href="#l1928">1928</a><td> /** @private {boolean} */<tr><td><a id="l1929"></a><a href="#l1929">1929</a><td> this.propagateUnhandledRejections_ = true;<tr><td><a id="l1930"></a><a href="#l1930">1930</a><td><tr><td><a id="l1931"></a><a href="#l1931">1931</a><td> /** @private {TaskQueue} */<tr><td><a id="l1932"></a><a href="#l1932">1932</a><td> this.activeQueue_ = null;<tr><td><a id="l1933"></a><a href="#l1933">1933</a><td><tr><td><a id="l1934"></a><a href="#l1934">1934</a><td> /** @private {Set&lt;TaskQueue&gt;} */<tr><td><a id="l1935"></a><a href="#l1935">1935</a><td> this.taskQueues_ = null;<tr><td><a id="l1936"></a><a href="#l1936">1936</a><td><tr><td><a id="l1937"></a><a href="#l1937">1937</a><td> /**<tr><td><a id="l1938"></a><a href="#l1938">1938</a><td> * Micro task that controls shutting down the control flow. Upon shut down,<tr><td><a id="l1939"></a><a href="#l1939">1939</a><td> * the flow will emit an<tr><td><a id="l1940"></a><a href="#l1940">1940</a><td> * {@link webdriver.promise.ControlFlow.EventType.IDLE} event. Idle events<tr><td><a id="l1941"></a><a href="#l1941">1941</a><td> * always follow a brief timeout in order to catch latent errors from the<tr><td><a id="l1942"></a><a href="#l1942">1942</a><td> * last completed task. If this task had a callback registered, but no<tr><td><a id="l1943"></a><a href="#l1943">1943</a><td> * errback, and the task fails, the unhandled failure would not be reported<tr><td><a id="l1944"></a><a href="#l1944">1944</a><td> * by the promise system until the next turn of the event loop:<tr><td><a id="l1945"></a><a href="#l1945">1945</a><td> *<tr><td><a id="l1946"></a><a href="#l1946">1946</a><td> * // Schedule 1 task that fails.<tr><td><a id="l1947"></a><a href="#l1947">1947</a><td> * var result = promise.controlFlow().schedule(&#39;example&#39;,<tr><td><a id="l1948"></a><a href="#l1948">1948</a><td> * function() { return promise.rejected(&#39;failed&#39;); });<tr><td><a id="l1949"></a><a href="#l1949">1949</a><td> * // Set a callback on the result. This delays reporting the unhandled<tr><td><a id="l1950"></a><a href="#l1950">1950</a><td> * // failure for 1 turn of the event loop.<tr><td><a id="l1951"></a><a href="#l1951">1951</a><td> * result.then(goog.nullFunction);<tr><td><a id="l1952"></a><a href="#l1952">1952</a><td> *<tr><td><a id="l1953"></a><a href="#l1953">1953</a><td> * @private {MicroTask}<tr><td><a id="l1954"></a><a href="#l1954">1954</a><td> */<tr><td><a id="l1955"></a><a href="#l1955">1955</a><td> this.shutdownTask_ = null;<tr><td><a id="l1956"></a><a href="#l1956">1956</a><td><tr><td><a id="l1957"></a><a href="#l1957">1957</a><td> /**<tr><td><a id="l1958"></a><a href="#l1958">1958</a><td> * ID for a long running interval used to keep a Node.js process running<tr><td><a id="l1959"></a><a href="#l1959">1959</a><td> * while a control flow&#39;s event loop is still working. This is a cheap hack<tr><td><a id="l1960"></a><a href="#l1960">1960</a><td> * required since JS events are only scheduled to run when there is<tr><td><a id="l1961"></a><a href="#l1961">1961</a><td> * _actually_ something to run. When a control flow is waiting on a task,<tr><td><a id="l1962"></a><a href="#l1962">1962</a><td> * there will be nothing in the JS event loop and the process would<tr><td><a id="l1963"></a><a href="#l1963">1963</a><td> * terminate without this.<tr><td><a id="l1964"></a><a href="#l1964">1964</a><td> *<tr><td><a id="l1965"></a><a href="#l1965">1965</a><td> * @private {?number}<tr><td><a id="l1966"></a><a href="#l1966">1966</a><td> */<tr><td><a id="l1967"></a><a href="#l1967">1967</a><td> this.hold_ = null;<tr><td><a id="l1968"></a><a href="#l1968">1968</a><td> },<tr><td><a id="l1969"></a><a href="#l1969">1969</a><td><tr><td><a id="l1970"></a><a href="#l1970">1970</a><td> /**<tr><td><a id="l1971"></a><a href="#l1971">1971</a><td> * Returns a string representation of this control flow, which is its current<tr><td><a id="l1972"></a><a href="#l1972">1972</a><td> * {@link #getSchedule() schedule}, sans task stack traces.<tr><td><a id="l1973"></a><a href="#l1973">1973</a><td> * @return {string} The string representation of this contorl flow.<tr><td><a id="l1974"></a><a href="#l1974">1974</a><td> * @override<tr><td><a id="l1975"></a><a href="#l1975">1975</a><td> */<tr><td><a id="l1976"></a><a href="#l1976">1976</a><td> toString: function() {<tr><td><a id="l1977"></a><a href="#l1977">1977</a><td> return this.getSchedule();<tr><td><a id="l1978"></a><a href="#l1978">1978</a><td> },<tr><td><a id="l1979"></a><a href="#l1979">1979</a><td><tr><td><a id="l1980"></a><a href="#l1980">1980</a><td> /**<tr><td><a id="l1981"></a><a href="#l1981">1981</a><td> * Sets whether any unhandled rejections should propagate up through the<tr><td><a id="l1982"></a><a href="#l1982">1982</a><td> * control flow stack and cause rejections within parent tasks. If error<tr><td><a id="l1983"></a><a href="#l1983">1983</a><td> * propagation is disabled, tasks will not be aborted when an unhandled<tr><td><a id="l1984"></a><a href="#l1984">1984</a><td> * promise rejection is detected, but the rejection _will_ trigger an<tr><td><a id="l1985"></a><a href="#l1985">1985</a><td> * {@link webdriver.promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION}<tr><td><a id="l1986"></a><a href="#l1986">1986</a><td> * event.<tr><td><a id="l1987"></a><a href="#l1987">1987</a><td> *<tr><td><a id="l1988"></a><a href="#l1988">1988</a><td> * The default behavior is to propagate all unhandled rejections. _The use<tr><td><a id="l1989"></a><a href="#l1989">1989</a><td> * of this option is highly discouraged._<tr><td><a id="l1990"></a><a href="#l1990">1990</a><td> *<tr><td><a id="l1991"></a><a href="#l1991">1991</a><td> * @param {boolean} propagate whether to propagate errors.<tr><td><a id="l1992"></a><a href="#l1992">1992</a><td> */<tr><td><a id="l1993"></a><a href="#l1993">1993</a><td> setPropagateUnhandledRejections: function(propagate) {<tr><td><a id="l1994"></a><a href="#l1994">1994</a><td> this.propagateUnhandledRejections_ = propagate;<tr><td><a id="l1995"></a><a href="#l1995">1995</a><td> },<tr><td><a id="l1996"></a><a href="#l1996">1996</a><td><tr><td><a id="l1997"></a><a href="#l1997">1997</a><td> /**<tr><td><a id="l1998"></a><a href="#l1998">1998</a><td> * @return {boolean} Whether this flow is currently idle.<tr><td><a id="l1999"></a><a href="#l1999">1999</a><td> */<tr><td><a id="l2000"></a><a href="#l2000">2000</a><td> isIdle: function() {<tr><td><a id="l2001"></a><a href="#l2001">2001</a><td> return !this.shutdownTask_ &amp;&amp; (!this.taskQueues_ || !this.taskQueues_.size);<tr><td><a id="l2002"></a><a href="#l2002">2002</a><td> },<tr><td><a id="l2003"></a><a href="#l2003">2003</a><td><tr><td><a id="l2004"></a><a href="#l2004">2004</a><td> /**<tr><td><a id="l2005"></a><a href="#l2005">2005</a><td> * Resets this instance, clearing its queue and removing all event listeners.<tr><td><a id="l2006"></a><a href="#l2006">2006</a><td> */<tr><td><a id="l2007"></a><a href="#l2007">2007</a><td> reset: function() {<tr><td><a id="l2008"></a><a href="#l2008">2008</a><td> this.cancelQueues_(new FlowResetError);<tr><td><a id="l2009"></a><a href="#l2009">2009</a><td> this.emit(promise.ControlFlow.EventType.RESET);<tr><td><a id="l2010"></a><a href="#l2010">2010</a><td> this.removeAllListeners();<tr><td><a id="l2011"></a><a href="#l2011">2011</a><td> this.cancelShutdown_();<tr><td><a id="l2012"></a><a href="#l2012">2012</a><td> },<tr><td><a id="l2013"></a><a href="#l2013">2013</a><td><tr><td><a id="l2014"></a><a href="#l2014">2014</a><td> /**<tr><td><a id="l2015"></a><a href="#l2015">2015</a><td> * Generates an annotated string describing the internal state of this control<tr><td><a id="l2016"></a><a href="#l2016">2016</a><td> * flow, including the currently executing as well as pending tasks. If<tr><td><a id="l2017"></a><a href="#l2017">2017</a><td> * {@code opt_includeStackTraces === true}, the string will include the<tr><td><a id="l2018"></a><a href="#l2018">2018</a><td> * stack trace from when each task was scheduled.<tr><td><a id="l2019"></a><a href="#l2019">2019</a><td> * @param {string=} opt_includeStackTraces Whether to include the stack traces<tr><td><a id="l2020"></a><a href="#l2020">2020</a><td> * from when each task was scheduled. Defaults to false.<tr><td><a id="l2021"></a><a href="#l2021">2021</a><td> * @return {string} String representation of this flow&#39;s internal state.<tr><td><a id="l2022"></a><a href="#l2022">2022</a><td> */<tr><td><a id="l2023"></a><a href="#l2023">2023</a><td> getSchedule: function(opt_includeStackTraces) {<tr><td><a id="l2024"></a><a href="#l2024">2024</a><td> var ret = &#39;ControlFlow::&#39; + goog.getUid(this);<tr><td><a id="l2025"></a><a href="#l2025">2025</a><td> var activeQueue = this.activeQueue_;<tr><td><a id="l2026"></a><a href="#l2026">2026</a><td> if (!this.taskQueues_ || !this.taskQueues_.size) {<tr><td><a id="l2027"></a><a href="#l2027">2027</a><td> return ret;<tr><td><a id="l2028"></a><a href="#l2028">2028</a><td> }<tr><td><a id="l2029"></a><a href="#l2029">2029</a><td> var childIndent = &#39;| &#39;;<tr><td><a id="l2030"></a><a href="#l2030">2030</a><td> for (var q of this.taskQueues_) {<tr><td><a id="l2031"></a><a href="#l2031">2031</a><td> ret += &#39;\n&#39; + printQ(q, childIndent);<tr><td><a id="l2032"></a><a href="#l2032">2032</a><td> }<tr><td><a id="l2033"></a><a href="#l2033">2033</a><td> return ret;<tr><td><a id="l2034"></a><a href="#l2034">2034</a><td><tr><td><a id="l2035"></a><a href="#l2035">2035</a><td> function printQ(q, indent) {<tr><td><a id="l2036"></a><a href="#l2036">2036</a><td> var ret = q.toString();<tr><td><a id="l2037"></a><a href="#l2037">2037</a><td> if (q === activeQueue) {<tr><td><a id="l2038"></a><a href="#l2038">2038</a><td> ret = &#39;(active) &#39; + ret;<tr><td><a id="l2039"></a><a href="#l2039">2039</a><td> }<tr><td><a id="l2040"></a><a href="#l2040">2040</a><td> var prefix = indent + childIndent;<tr><td><a id="l2041"></a><a href="#l2041">2041</a><td> if (q.pending_) {<tr><td><a id="l2042"></a><a href="#l2042">2042</a><td> if (q.pending_.q.state_ !== TaskQueueState.FINISHED) {<tr><td><a id="l2043"></a><a href="#l2043">2043</a><td> ret += &#39;\n&#39; + prefix + &#39;(pending) &#39; + q.pending_.task;<tr><td><a id="l2044"></a><a href="#l2044">2044</a><td> ret += &#39;\n&#39; + printQ(q.pending_.q, prefix + childIndent);<tr><td><a id="l2045"></a><a href="#l2045">2045</a><td> } else {<tr><td><a id="l2046"></a><a href="#l2046">2046</a><td> ret += &#39;\n&#39; + prefix + &#39;(blocked) &#39; + q.pending_.task;<tr><td><a id="l2047"></a><a href="#l2047">2047</a><td> }<tr><td><a id="l2048"></a><a href="#l2048">2048</a><td> }<tr><td><a id="l2049"></a><a href="#l2049">2049</a><td> if (q.interrupts_) {<tr><td><a id="l2050"></a><a href="#l2050">2050</a><td> q.interrupts_.forEach((task) =&gt; {<tr><td><a id="l2051"></a><a href="#l2051">2051</a><td> ret += &#39;\n&#39; + prefix + task;<tr><td><a id="l2052"></a><a href="#l2052">2052</a><td> });<tr><td><a id="l2053"></a><a href="#l2053">2053</a><td> }<tr><td><a id="l2054"></a><a href="#l2054">2054</a><td> if (q.tasks_) {<tr><td><a id="l2055"></a><a href="#l2055">2055</a><td> q.tasks_.forEach((task) =&gt; ret += printTask(task, &#39;\n&#39; + prefix));<tr><td><a id="l2056"></a><a href="#l2056">2056</a><td> }<tr><td><a id="l2057"></a><a href="#l2057">2057</a><td> return indent + ret;<tr><td><a id="l2058"></a><a href="#l2058">2058</a><td> }<tr><td><a id="l2059"></a><a href="#l2059">2059</a><td><tr><td><a id="l2060"></a><a href="#l2060">2060</a><td> function printTask(task, prefix) {<tr><td><a id="l2061"></a><a href="#l2061">2061</a><td> var ret = prefix + task;<tr><td><a id="l2062"></a><a href="#l2062">2062</a><td> if (opt_includeStackTraces &amp;&amp; task.promise.stack_) {<tr><td><a id="l2063"></a><a href="#l2063">2063</a><td> ret += prefix + childIndent<tr><td><a id="l2064"></a><a href="#l2064">2064</a><td> + (task.promise.stack_.stack || task.promise.stack_)<tr><td><a id="l2065"></a><a href="#l2065">2065</a><td> .replace(/\n/g, prefix);<tr><td><a id="l2066"></a><a href="#l2066">2066</a><td> }<tr><td><a id="l2067"></a><a href="#l2067">2067</a><td> return ret;<tr><td><a id="l2068"></a><a href="#l2068">2068</a><td> }<tr><td><a id="l2069"></a><a href="#l2069">2069</a><td> },<tr><td><a id="l2070"></a><a href="#l2070">2070</a><td><tr><td><a id="l2071"></a><a href="#l2071">2071</a><td> /**<tr><td><a id="l2072"></a><a href="#l2072">2072</a><td> * Returns the currently actively task queue for this flow. If there is no<tr><td><a id="l2073"></a><a href="#l2073">2073</a><td> * active queue, one will be created.<tr><td><a id="l2074"></a><a href="#l2074">2074</a><td> * @return {!TaskQueue} the currently active task queue for this flow.<tr><td><a id="l2075"></a><a href="#l2075">2075</a><td> * @private<tr><td><a id="l2076"></a><a href="#l2076">2076</a><td> */<tr><td><a id="l2077"></a><a href="#l2077">2077</a><td> getActiveQueue_: function() {<tr><td><a id="l2078"></a><a href="#l2078">2078</a><td> if (this.activeQueue_) {<tr><td><a id="l2079"></a><a href="#l2079">2079</a><td> return this.activeQueue_;<tr><td><a id="l2080"></a><a href="#l2080">2080</a><td> }<tr><td><a id="l2081"></a><a href="#l2081">2081</a><td><tr><td><a id="l2082"></a><a href="#l2082">2082</a><td> this.activeQueue_ = new TaskQueue(this);<tr><td><a id="l2083"></a><a href="#l2083">2083</a><td> if (!this.taskQueues_) {<tr><td><a id="l2084"></a><a href="#l2084">2084</a><td> this.taskQueues_ = new Set();<tr><td><a id="l2085"></a><a href="#l2085">2085</a><td> }<tr><td><a id="l2086"></a><a href="#l2086">2086</a><td> this.taskQueues_.add(this.activeQueue_);<tr><td><a id="l2087"></a><a href="#l2087">2087</a><td> this.activeQueue_<tr><td><a id="l2088"></a><a href="#l2088">2088</a><td> .once(&#39;end&#39;, this.onQueueEnd_, this)<tr><td><a id="l2089"></a><a href="#l2089">2089</a><td> .once(&#39;error&#39;, this.onQueueError_, this);<tr><td><a id="l2090"></a><a href="#l2090">2090</a><td><tr><td><a id="l2091"></a><a href="#l2091">2091</a><td> asyncRun(() =&gt; this.activeQueue_ = null, this);<tr><td><a id="l2092"></a><a href="#l2092">2092</a><td> this.activeQueue_.start();<tr><td><a id="l2093"></a><a href="#l2093">2093</a><td> return this.activeQueue_;<tr><td><a id="l2094"></a><a href="#l2094">2094</a><td> },<tr><td><a id="l2095"></a><a href="#l2095">2095</a><td><tr><td><a id="l2096"></a><a href="#l2096">2096</a><td> /**<tr><td><a id="l2097"></a><a href="#l2097">2097</a><td> * Schedules a task for execution. If there is nothing currently in the<tr><td><a id="l2098"></a><a href="#l2098">2098</a><td> * queue, the task will be executed in the next turn of the event loop. If<tr><td><a id="l2099"></a><a href="#l2099">2099</a><td> * the task function is a generator, the task will be executed using<tr><td><a id="l2100"></a><a href="#l2100">2100</a><td> * {@link webdriver.promise.consume}.<tr><td><a id="l2101"></a><a href="#l2101">2101</a><td> *<tr><td><a id="l2102"></a><a href="#l2102">2102</a><td> * @param {function(): (T|promise.Promise&lt;T&gt;)} fn The function to<tr><td><a id="l2103"></a><a href="#l2103">2103</a><td> * call to start the task. If the function returns a<tr><td><a id="l2104"></a><a href="#l2104">2104</a><td> * {@link webdriver.promise.Promise}, this instance will wait for it to be<tr><td><a id="l2105"></a><a href="#l2105">2105</a><td> * resolved before starting the next task.<tr><td><a id="l2106"></a><a href="#l2106">2106</a><td> * @param {string=} opt_description A description of the task.<tr><td><a id="l2107"></a><a href="#l2107">2107</a><td> * @return {!promise.Promise&lt;T&gt;} A promise that will be resolved<tr><td><a id="l2108"></a><a href="#l2108">2108</a><td> * with the result of the action.<tr><td><a id="l2109"></a><a href="#l2109">2109</a><td> * @template T<tr><td><a id="l2110"></a><a href="#l2110">2110</a><td> */<tr><td><a id="l2111"></a><a href="#l2111">2111</a><td> execute: function(fn, opt_description) {<tr><td><a id="l2112"></a><a href="#l2112">2112</a><td> if (promise.isGenerator(fn)) {<tr><td><a id="l2113"></a><a href="#l2113">2113</a><td> fn = goog.partial(promise.consume, fn);<tr><td><a id="l2114"></a><a href="#l2114">2114</a><td> }<tr><td><a id="l2115"></a><a href="#l2115">2115</a><td><tr><td><a id="l2116"></a><a href="#l2116">2116</a><td> if (!this.hold_) {<tr><td><a id="l2117"></a><a href="#l2117">2117</a><td> var holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js<tr><td><a id="l2118"></a><a href="#l2118">2118</a><td> this.hold_ = setInterval(goog.nullFunction, holdIntervalMs);<tr><td><a id="l2119"></a><a href="#l2119">2119</a><td> }<tr><td><a id="l2120"></a><a href="#l2120">2120</a><td><tr><td><a id="l2121"></a><a href="#l2121">2121</a><td> var task = new Task(<tr><td><a id="l2122"></a><a href="#l2122">2122</a><td> this, fn, opt_description || &#39;&lt;anonymous&gt;&#39;,<tr><td><a id="l2123"></a><a href="#l2123">2123</a><td> {name: &#39;Task&#39;, top: promise.ControlFlow.prototype.execute});<tr><td><a id="l2124"></a><a href="#l2124">2124</a><td><tr><td><a id="l2125"></a><a href="#l2125">2125</a><td> var q = this.getActiveQueue_();<tr><td><a id="l2126"></a><a href="#l2126">2126</a><td> q.enqueue(task);<tr><td><a id="l2127"></a><a href="#l2127">2127</a><td> this.emit(promise.ControlFlow.EventType.SCHEDULE_TASK, task.description);<tr><td><a id="l2128"></a><a href="#l2128">2128</a><td> return task.promise;<tr><td><a id="l2129"></a><a href="#l2129">2129</a><td> },<tr><td><a id="l2130"></a><a href="#l2130">2130</a><td><tr><td><a id="l2131"></a><a href="#l2131">2131</a><td> /**<tr><td><a id="l2132"></a><a href="#l2132">2132</a><td> * Inserts a {@code setTimeout} into the command queue. This is equivalent to<tr><td><a id="l2133"></a><a href="#l2133">2133</a><td> * a thread sleep in a synchronous programming language.<tr><td><a id="l2134"></a><a href="#l2134">2134</a><td> *<tr><td><a id="l2135"></a><a href="#l2135">2135</a><td> * @param {number} ms The timeout delay, in milliseconds.<tr><td><a id="l2136"></a><a href="#l2136">2136</a><td> * @param {string=} opt_description A description to accompany the timeout.<tr><td><a id="l2137"></a><a href="#l2137">2137</a><td> * @return {!promise.Promise} A promise that will be resolved with<tr><td><a id="l2138"></a><a href="#l2138">2138</a><td> * the result of the action.<tr><td><a id="l2139"></a><a href="#l2139">2139</a><td> */<tr><td><a id="l2140"></a><a href="#l2140">2140</a><td> timeout: function(ms, opt_description) {<tr><td><a id="l2141"></a><a href="#l2141">2141</a><td> return this.execute(function() {<tr><td><a id="l2142"></a><a href="#l2142">2142</a><td> return promise.delayed(ms);<tr><td><a id="l2143"></a><a href="#l2143">2143</a><td> }, opt_description);<tr><td><a id="l2144"></a><a href="#l2144">2144</a><td> },<tr><td><a id="l2145"></a><a href="#l2145">2145</a><td><tr><td><a id="l2146"></a><a href="#l2146">2146</a><td> /**<tr><td><a id="l2147"></a><a href="#l2147">2147</a><td> * Schedules a task that shall wait for a condition to hold. Each condition<tr><td><a id="l2148"></a><a href="#l2148">2148</a><td> * function may return any value, but it will always be evaluated as a<tr><td><a id="l2149"></a><a href="#l2149">2149</a><td> * boolean.<tr><td><a id="l2150"></a><a href="#l2150">2150</a><td> *<tr><td><a id="l2151"></a><a href="#l2151">2151</a><td> * Condition functions may schedule sub-tasks with this instance, however,<tr><td><a id="l2152"></a><a href="#l2152">2152</a><td> * their execution time will be factored into whether a wait has timed out.<tr><td><a id="l2153"></a><a href="#l2153">2153</a><td> *<tr><td><a id="l2154"></a><a href="#l2154">2154</a><td> * In the event a condition returns a Promise, the polling loop will wait for<tr><td><a id="l2155"></a><a href="#l2155">2155</a><td> * it to be resolved before evaluating whether the condition has been<tr><td><a id="l2156"></a><a href="#l2156">2156</a><td> * satisfied. The resolution time for a promise is factored into whether a<tr><td><a id="l2157"></a><a href="#l2157">2157</a><td> * wait has timed out.<tr><td><a id="l2158"></a><a href="#l2158">2158</a><td> *<tr><td><a id="l2159"></a><a href="#l2159">2159</a><td> * If the condition function throws, or returns a rejected promise, the<tr><td><a id="l2160"></a><a href="#l2160">2160</a><td> * wait task will fail.<tr><td><a id="l2161"></a><a href="#l2161">2161</a><td> *<tr><td><a id="l2162"></a><a href="#l2162">2162</a><td> * If the condition is defined as a promise, the flow will wait for it to<tr><td><a id="l2163"></a><a href="#l2163">2163</a><td> * settle. If the timeout expires before the promise settles, the promise<tr><td><a id="l2164"></a><a href="#l2164">2164</a><td> * returned by this function will be rejected.<tr><td><a id="l2165"></a><a href="#l2165">2165</a><td> *<tr><td><a id="l2166"></a><a href="#l2166">2166</a><td> * If this function is invoked with `timeout === 0`, or the timeout is<tr><td><a id="l2167"></a><a href="#l2167">2167</a><td> * omitted, the flow will wait indefinitely for the condition to be satisfied.<tr><td><a id="l2168"></a><a href="#l2168">2168</a><td> *<tr><td><a id="l2169"></a><a href="#l2169">2169</a><td> * @param {(!promise.Promise&lt;T&gt;|function())} condition The condition to poll,<tr><td><a id="l2170"></a><a href="#l2170">2170</a><td> * or a promise to wait on.<tr><td><a id="l2171"></a><a href="#l2171">2171</a><td> * @param {number=} opt_timeout How long to wait, in milliseconds, for the<tr><td><a id="l2172"></a><a href="#l2172">2172</a><td> * condition to hold before timing out. If omitted, the flow will wait<tr><td><a id="l2173"></a><a href="#l2173">2173</a><td> * indefinitely.<tr><td><a id="l2174"></a><a href="#l2174">2174</a><td> * @param {string=} opt_message An optional error message to include if the<tr><td><a id="l2175"></a><a href="#l2175">2175</a><td> * wait times out; defaults to the empty string.<tr><td><a id="l2176"></a><a href="#l2176">2176</a><td> * @return {!promise.Promise&lt;T&gt;} A promise that will be fulfilled<tr><td><a id="l2177"></a><a href="#l2177">2177</a><td> * when the condition has been satisified. The promise shall be rejected<tr><td><a id="l2178"></a><a href="#l2178">2178</a><td> * if the wait times out waiting for the condition.<tr><td><a id="l2179"></a><a href="#l2179">2179</a><td> * @throws {TypeError} If condition is not a function or promise or if timeout<tr><td><a id="l2180"></a><a href="#l2180">2180</a><td> * is not a number &gt;= 0.<tr><td><a id="l2181"></a><a href="#l2181">2181</a><td> * @template T<tr><td><a id="l2182"></a><a href="#l2182">2182</a><td> */<tr><td><a id="l2183"></a><a href="#l2183">2183</a><td> wait: function(condition, opt_timeout, opt_message) {<tr><td><a id="l2184"></a><a href="#l2184">2184</a><td> var timeout = opt_timeout || 0;<tr><td><a id="l2185"></a><a href="#l2185">2185</a><td> if (!goog.isNumber(timeout) || timeout &lt; 0) {<tr><td><a id="l2186"></a><a href="#l2186">2186</a><td> throw TypeError(&#39;timeout must be a number &gt;= 0: &#39; + timeout);<tr><td><a id="l2187"></a><a href="#l2187">2187</a><td> }<tr><td><a id="l2188"></a><a href="#l2188">2188</a><td><tr><td><a id="l2189"></a><a href="#l2189">2189</a><td> if (promise.isPromise(condition)) {<tr><td><a id="l2190"></a><a href="#l2190">2190</a><td> return this.execute(function() {<tr><td><a id="l2191"></a><a href="#l2191">2191</a><td> if (!timeout) {<tr><td><a id="l2192"></a><a href="#l2192">2192</a><td> return condition;<tr><td><a id="l2193"></a><a href="#l2193">2193</a><td> }<tr><td><a id="l2194"></a><a href="#l2194">2194</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l2195"></a><a href="#l2195">2195</a><td> var start = goog.now();<tr><td><a id="l2196"></a><a href="#l2196">2196</a><td> var timer = setTimeout(function() {<tr><td><a id="l2197"></a><a href="#l2197">2197</a><td> timer = null;<tr><td><a id="l2198"></a><a href="#l2198">2198</a><td> reject(Error((opt_message ? opt_message + &#39;\n&#39; : &#39;&#39;) +<tr><td><a id="l2199"></a><a href="#l2199">2199</a><td> &#39;Timed out waiting for promise to resolve after &#39; +<tr><td><a id="l2200"></a><a href="#l2200">2200</a><td> (goog.now() - start) + &#39;ms&#39;));<tr><td><a id="l2201"></a><a href="#l2201">2201</a><td> }, timeout);<tr><td><a id="l2202"></a><a href="#l2202">2202</a><td><tr><td><a id="l2203"></a><a href="#l2203">2203</a><td> /** @type {Thenable} */(condition).then(<tr><td><a id="l2204"></a><a href="#l2204">2204</a><td> function(value) {<tr><td><a id="l2205"></a><a href="#l2205">2205</a><td> timer &amp;&amp; clearTimeout(timer);<tr><td><a id="l2206"></a><a href="#l2206">2206</a><td> fulfill(value);<tr><td><a id="l2207"></a><a href="#l2207">2207</a><td> },<tr><td><a id="l2208"></a><a href="#l2208">2208</a><td> function(error) {<tr><td><a id="l2209"></a><a href="#l2209">2209</a><td> timer &amp;&amp; clearTimeout(timer);<tr><td><a id="l2210"></a><a href="#l2210">2210</a><td> reject(error);<tr><td><a id="l2211"></a><a href="#l2211">2211</a><td> });<tr><td><a id="l2212"></a><a href="#l2212">2212</a><td> });<tr><td><a id="l2213"></a><a href="#l2213">2213</a><td> }, opt_message || &#39;&lt;anonymous wait: promise resolution&gt;&#39;);<tr><td><a id="l2214"></a><a href="#l2214">2214</a><td> }<tr><td><a id="l2215"></a><a href="#l2215">2215</a><td><tr><td><a id="l2216"></a><a href="#l2216">2216</a><td> if (!goog.isFunction(condition)) {<tr><td><a id="l2217"></a><a href="#l2217">2217</a><td> throw TypeError(&#39;Invalid condition; must be a function or promise: &#39; +<tr><td><a id="l2218"></a><a href="#l2218">2218</a><td> goog.typeOf(condition));<tr><td><a id="l2219"></a><a href="#l2219">2219</a><td> }<tr><td><a id="l2220"></a><a href="#l2220">2220</a><td><tr><td><a id="l2221"></a><a href="#l2221">2221</a><td> if (promise.isGenerator(condition)) {<tr><td><a id="l2222"></a><a href="#l2222">2222</a><td> condition = goog.partial(promise.consume, condition);<tr><td><a id="l2223"></a><a href="#l2223">2223</a><td> }<tr><td><a id="l2224"></a><a href="#l2224">2224</a><td><tr><td><a id="l2225"></a><a href="#l2225">2225</a><td> var self = this;<tr><td><a id="l2226"></a><a href="#l2226">2226</a><td> return this.execute(function() {<tr><td><a id="l2227"></a><a href="#l2227">2227</a><td> var startTime = goog.now();<tr><td><a id="l2228"></a><a href="#l2228">2228</a><td> return new promise.Promise(function(fulfill, reject) {<tr><td><a id="l2229"></a><a href="#l2229">2229</a><td> pollCondition();<tr><td><a id="l2230"></a><a href="#l2230">2230</a><td><tr><td><a id="l2231"></a><a href="#l2231">2231</a><td> function pollCondition() {<tr><td><a id="l2232"></a><a href="#l2232">2232</a><td> var conditionFn = /** @type {function()} */(condition);<tr><td><a id="l2233"></a><a href="#l2233">2233</a><td> self.execute(conditionFn).then(function(value) {<tr><td><a id="l2234"></a><a href="#l2234">2234</a><td> var elapsed = goog.now() - startTime;<tr><td><a id="l2235"></a><a href="#l2235">2235</a><td> if (!!value) {<tr><td><a id="l2236"></a><a href="#l2236">2236</a><td> fulfill(value);<tr><td><a id="l2237"></a><a href="#l2237">2237</a><td> } else if (timeout &amp;&amp; elapsed &gt;= timeout) {<tr><td><a id="l2238"></a><a href="#l2238">2238</a><td> reject(new Error((opt_message ? opt_message + &#39;\n&#39; : &#39;&#39;) +<tr><td><a id="l2239"></a><a href="#l2239">2239</a><td> &#39;Wait timed out after &#39; + elapsed + &#39;ms&#39;));<tr><td><a id="l2240"></a><a href="#l2240">2240</a><td> } else {<tr><td><a id="l2241"></a><a href="#l2241">2241</a><td> // Do not use asyncRun here because we need a non-micro yield<tr><td><a id="l2242"></a><a href="#l2242">2242</a><td> // here so the UI thread is given a chance when running in a<tr><td><a id="l2243"></a><a href="#l2243">2243</a><td> // browser.<tr><td><a id="l2244"></a><a href="#l2244">2244</a><td> setTimeout(pollCondition, 0);<tr><td><a id="l2245"></a><a href="#l2245">2245</a><td> }<tr><td><a id="l2246"></a><a href="#l2246">2246</a><td> }, reject);<tr><td><a id="l2247"></a><a href="#l2247">2247</a><td> }<tr><td><a id="l2248"></a><a href="#l2248">2248</a><td> });<tr><td><a id="l2249"></a><a href="#l2249">2249</a><td> }, opt_message || &#39;&lt;anonymous wait&gt;&#39;);<tr><td><a id="l2250"></a><a href="#l2250">2250</a><td> },<tr><td><a id="l2251"></a><a href="#l2251">2251</a><td><tr><td><a id="l2252"></a><a href="#l2252">2252</a><td> /**<tr><td><a id="l2253"></a><a href="#l2253">2253</a><td> * Executes a function in the next available turn of the JavaScript event<tr><td><a id="l2254"></a><a href="#l2254">2254</a><td> * loop. This ensures the function runs with its own task queue and any<tr><td><a id="l2255"></a><a href="#l2255">2255</a><td> * scheduled tasks will run in &quot;parallel&quot; to those scheduled in the current<tr><td><a id="l2256"></a><a href="#l2256">2256</a><td> * function.<tr><td><a id="l2257"></a><a href="#l2257">2257</a><td> *<tr><td><a id="l2258"></a><a href="#l2258">2258</a><td> * flow.execute(() =&gt; console.log(&#39;a&#39;));<tr><td><a id="l2259"></a><a href="#l2259">2259</a><td> * flow.execute(() =&gt; console.log(&#39;b&#39;));<tr><td><a id="l2260"></a><a href="#l2260">2260</a><td> * flow.execute(() =&gt; console.log(&#39;c&#39;));<tr><td><a id="l2261"></a><a href="#l2261">2261</a><td> * flow.async(() =&gt; {<tr><td><a id="l2262"></a><a href="#l2262">2262</a><td> * flow.execute(() =&gt; console.log(&#39;d&#39;));<tr><td><a id="l2263"></a><a href="#l2263">2263</a><td> * flow.execute(() =&gt; console.log(&#39;e&#39;));<tr><td><a id="l2264"></a><a href="#l2264">2264</a><td> * });<tr><td><a id="l2265"></a><a href="#l2265">2265</a><td> * flow.async(() =&gt; {<tr><td><a id="l2266"></a><a href="#l2266">2266</a><td> * flow.execute(() =&gt; console.log(&#39;f&#39;));<tr><td><a id="l2267"></a><a href="#l2267">2267</a><td> * flow.execute(() =&gt; console.log(&#39;g&#39;));<tr><td><a id="l2268"></a><a href="#l2268">2268</a><td> * });<tr><td><a id="l2269"></a><a href="#l2269">2269</a><td> * flow.once(&#39;idle&#39;, () =&gt; console.log(&#39;fin&#39;));<tr><td><a id="l2270"></a><a href="#l2270">2270</a><td> * // a<tr><td><a id="l2271"></a><a href="#l2271">2271</a><td> * // d<tr><td><a id="l2272"></a><a href="#l2272">2272</a><td> * // f<tr><td><a id="l2273"></a><a href="#l2273">2273</a><td> * // b<tr><td><a id="l2274"></a><a href="#l2274">2274</a><td> * // e<tr><td><a id="l2275"></a><a href="#l2275">2275</a><td> * // g<tr><td><a id="l2276"></a><a href="#l2276">2276</a><td> * // c<tr><td><a id="l2277"></a><a href="#l2277">2277</a><td> * // fin<tr><td><a id="l2278"></a><a href="#l2278">2278</a><td> *<tr><td><a id="l2279"></a><a href="#l2279">2279</a><td> * If the function itself throws, the error will be treated the same as an<tr><td><a id="l2280"></a><a href="#l2280">2280</a><td> * unhandled rejection within the control flow.<tr><td><a id="l2281"></a><a href="#l2281">2281</a><td> *<tr><td><a id="l2282"></a><a href="#l2282">2282</a><td> * __NOTE__: This function is considered _unstable_.<tr><td><a id="l2283"></a><a href="#l2283">2283</a><td> *<tr><td><a id="l2284"></a><a href="#l2284">2284</a><td> * @param {!Function} fn The function to execute.<tr><td><a id="l2285"></a><a href="#l2285">2285</a><td> * @param {Object=} opt_self The object in whose context to run the function.<tr><td><a id="l2286"></a><a href="#l2286">2286</a><td> * @param {...*} var_args Any arguments to pass to the function.<tr><td><a id="l2287"></a><a href="#l2287">2287</a><td> */<tr><td><a id="l2288"></a><a href="#l2288">2288</a><td> async: function(fn, opt_self, var_args) {<tr><td><a id="l2289"></a><a href="#l2289">2289</a><td> asyncRun(function() {<tr><td><a id="l2290"></a><a href="#l2290">2290</a><td> // Clear any lingering queues, forces getActiveQueue_ to create a new one.<tr><td><a id="l2291"></a><a href="#l2291">2291</a><td> this.activeQueue_ = null;<tr><td><a id="l2292"></a><a href="#l2292">2292</a><td> var q = this.getActiveQueue_();<tr><td><a id="l2293"></a><a href="#l2293">2293</a><td> try {<tr><td><a id="l2294"></a><a href="#l2294">2294</a><td> q.execute_(fn.bind(opt_self, var_args));<tr><td><a id="l2295"></a><a href="#l2295">2295</a><td> } catch (ex) {<tr><td><a id="l2296"></a><a href="#l2296">2296</a><td> var cancellationError = promise.CancellationError.wrap(ex,<tr><td><a id="l2297"></a><a href="#l2297">2297</a><td> &#39;Function passed to ControlFlow.async() threw&#39;);<tr><td><a id="l2298"></a><a href="#l2298">2298</a><td> cancellationError.silent_ = true;<tr><td><a id="l2299"></a><a href="#l2299">2299</a><td> q.abort_(cancellationError);<tr><td><a id="l2300"></a><a href="#l2300">2300</a><td> } finally {<tr><td><a id="l2301"></a><a href="#l2301">2301</a><td> this.activeQueue_ = null;<tr><td><a id="l2302"></a><a href="#l2302">2302</a><td> }<tr><td><a id="l2303"></a><a href="#l2303">2303</a><td> }, this);<tr><td><a id="l2304"></a><a href="#l2304">2304</a><td> },<tr><td><a id="l2305"></a><a href="#l2305">2305</a><td><tr><td><a id="l2306"></a><a href="#l2306">2306</a><td> /**<tr><td><a id="l2307"></a><a href="#l2307">2307</a><td> * Event handler for when a task queue is exhausted. This starts the shutdown<tr><td><a id="l2308"></a><a href="#l2308">2308</a><td> * sequence for this instance if there are no remaining task queues: after<tr><td><a id="l2309"></a><a href="#l2309">2309</a><td> * one turn of the event loop, this object will emit the<tr><td><a id="l2310"></a><a href="#l2310">2310</a><td> * {@link webdriver.promise.ControlFlow.EventType.IDLE IDLE} event to signal<tr><td><a id="l2311"></a><a href="#l2311">2311</a><td> * listeners that it has completed. During this wait, if another task is<tr><td><a id="l2312"></a><a href="#l2312">2312</a><td> * scheduled, the shutdown will be aborted.<tr><td><a id="l2313"></a><a href="#l2313">2313</a><td> *<tr><td><a id="l2314"></a><a href="#l2314">2314</a><td> * @param {!TaskQueue} q the completed task queue.<tr><td><a id="l2315"></a><a href="#l2315">2315</a><td> * @private<tr><td><a id="l2316"></a><a href="#l2316">2316</a><td> */<tr><td><a id="l2317"></a><a href="#l2317">2317</a><td> onQueueEnd_: function(q) {<tr><td><a id="l2318"></a><a href="#l2318">2318</a><td> if (!this.taskQueues_) {<tr><td><a id="l2319"></a><a href="#l2319">2319</a><td> return;<tr><td><a id="l2320"></a><a href="#l2320">2320</a><td> }<tr><td><a id="l2321"></a><a href="#l2321">2321</a><td> this.taskQueues_.delete(q);<tr><td><a id="l2322"></a><a href="#l2322">2322</a><td><tr><td><a id="l2323"></a><a href="#l2323">2323</a><td> vlog(1, () =&gt; q + &#39; has finished&#39;);<tr><td><a id="l2324"></a><a href="#l2324">2324</a><td> vlog(1, () =&gt; this.taskQueues_.size + &#39; queues remain\n&#39; + this, this);<tr><td><a id="l2325"></a><a href="#l2325">2325</a><td><tr><td><a id="l2326"></a><a href="#l2326">2326</a><td> if (!this.taskQueues_.size) {<tr><td><a id="l2327"></a><a href="#l2327">2327</a><td> asserts.assert(!this.shutdownTask_, &#39;Already have a shutdown task??&#39;);<tr><td><a id="l2328"></a><a href="#l2328">2328</a><td> this.shutdownTask_ = new MicroTask(this.shutdown_, this);<tr><td><a id="l2329"></a><a href="#l2329">2329</a><td> }<tr><td><a id="l2330"></a><a href="#l2330">2330</a><td> },<tr><td><a id="l2331"></a><a href="#l2331">2331</a><td><tr><td><a id="l2332"></a><a href="#l2332">2332</a><td> /**<tr><td><a id="l2333"></a><a href="#l2333">2333</a><td> * Event handler for when a task queue terminates with an error. This triggers<tr><td><a id="l2334"></a><a href="#l2334">2334</a><td> * the cancellation of all other task queues and a<tr><td><a id="l2335"></a><a href="#l2335">2335</a><td> * {@link webdriver.promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.<tr><td><a id="l2336"></a><a href="#l2336">2336</a><td> * If there are no error event listeners registered with this instance, the<tr><td><a id="l2337"></a><a href="#l2337">2337</a><td> * error will be rethrown to the global error handler.<tr><td><a id="l2338"></a><a href="#l2338">2338</a><td> *<tr><td><a id="l2339"></a><a href="#l2339">2339</a><td> * @param {*} error the error that caused the task queue to terminate.<tr><td><a id="l2340"></a><a href="#l2340">2340</a><td> * @param {!TaskQueue} q the task queue.<tr><td><a id="l2341"></a><a href="#l2341">2341</a><td> * @private<tr><td><a id="l2342"></a><a href="#l2342">2342</a><td> */<tr><td><a id="l2343"></a><a href="#l2343">2343</a><td> onQueueError_: function(error, q) {<tr><td><a id="l2344"></a><a href="#l2344">2344</a><td> if (this.taskQueues_) {<tr><td><a id="l2345"></a><a href="#l2345">2345</a><td> this.taskQueues_.delete(q);<tr><td><a id="l2346"></a><a href="#l2346">2346</a><td> }<tr><td><a id="l2347"></a><a href="#l2347">2347</a><td> this.cancelQueues_(promise.CancellationError.wrap(<tr><td><a id="l2348"></a><a href="#l2348">2348</a><td> error, &#39;There was an uncaught error in the control flow&#39;));<tr><td><a id="l2349"></a><a href="#l2349">2349</a><td> this.cancelShutdown_();<tr><td><a id="l2350"></a><a href="#l2350">2350</a><td> this.cancelHold_();<tr><td><a id="l2351"></a><a href="#l2351">2351</a><td><tr><td><a id="l2352"></a><a href="#l2352">2352</a><td> var listeners = this.listeners(<tr><td><a id="l2353"></a><a href="#l2353">2353</a><td> promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);<tr><td><a id="l2354"></a><a href="#l2354">2354</a><td> if (!listeners.length) {<tr><td><a id="l2355"></a><a href="#l2355">2355</a><td> throwException(error);<tr><td><a id="l2356"></a><a href="#l2356">2356</a><td> } else {<tr><td><a id="l2357"></a><a href="#l2357">2357</a><td> this.reportUncaughtException_(error);<tr><td><a id="l2358"></a><a href="#l2358">2358</a><td> }<tr><td><a id="l2359"></a><a href="#l2359">2359</a><td> },<tr><td><a id="l2360"></a><a href="#l2360">2360</a><td><tr><td><a id="l2361"></a><a href="#l2361">2361</a><td> /**<tr><td><a id="l2362"></a><a href="#l2362">2362</a><td> * Cancels all remaining task queues.<tr><td><a id="l2363"></a><a href="#l2363">2363</a><td> * @param {!promise.CancellationError} reason The cancellation reason.<tr><td><a id="l2364"></a><a href="#l2364">2364</a><td> * @private<tr><td><a id="l2365"></a><a href="#l2365">2365</a><td> */<tr><td><a id="l2366"></a><a href="#l2366">2366</a><td> cancelQueues_: function(reason) {<tr><td><a id="l2367"></a><a href="#l2367">2367</a><td> reason.silent_ = true;<tr><td><a id="l2368"></a><a href="#l2368">2368</a><td> if (this.taskQueues_) {<tr><td><a id="l2369"></a><a href="#l2369">2369</a><td> for (var q of this.taskQueues_) {<tr><td><a id="l2370"></a><a href="#l2370">2370</a><td> q.removeAllListeners();<tr><td><a id="l2371"></a><a href="#l2371">2371</a><td> q.abort_(reason);<tr><td><a id="l2372"></a><a href="#l2372">2372</a><td> }<tr><td><a id="l2373"></a><a href="#l2373">2373</a><td> this.taskQueues_.clear();<tr><td><a id="l2374"></a><a href="#l2374">2374</a><td> this.taskQueues_ = null;<tr><td><a id="l2375"></a><a href="#l2375">2375</a><td> }<tr><td><a id="l2376"></a><a href="#l2376">2376</a><td> },<tr><td><a id="l2377"></a><a href="#l2377">2377</a><td><tr><td><a id="l2378"></a><a href="#l2378">2378</a><td> /**<tr><td><a id="l2379"></a><a href="#l2379">2379</a><td> * Reports an uncaught exception using a<tr><td><a id="l2380"></a><a href="#l2380">2380</a><td> * {@link webdriver.promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.<tr><td><a id="l2381"></a><a href="#l2381">2381</a><td> *<tr><td><a id="l2382"></a><a href="#l2382">2382</a><td> * @param {*} e the error to report.<tr><td><a id="l2383"></a><a href="#l2383">2383</a><td> * @private<tr><td><a id="l2384"></a><a href="#l2384">2384</a><td> */<tr><td><a id="l2385"></a><a href="#l2385">2385</a><td> reportUncaughtException_: function(e) {<tr><td><a id="l2386"></a><a href="#l2386">2386</a><td> this.emit(promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION, e);<tr><td><a id="l2387"></a><a href="#l2387">2387</a><td> },<tr><td><a id="l2388"></a><a href="#l2388">2388</a><td><tr><td><a id="l2389"></a><a href="#l2389">2389</a><td> /** @private */<tr><td><a id="l2390"></a><a href="#l2390">2390</a><td> cancelHold_: function() {<tr><td><a id="l2391"></a><a href="#l2391">2391</a><td> if (this.hold_) {<tr><td><a id="l2392"></a><a href="#l2392">2392</a><td> clearInterval(this.hold_);<tr><td><a id="l2393"></a><a href="#l2393">2393</a><td> this.hold_ = null;<tr><td><a id="l2394"></a><a href="#l2394">2394</a><td> }<tr><td><a id="l2395"></a><a href="#l2395">2395</a><td> },<tr><td><a id="l2396"></a><a href="#l2396">2396</a><td><tr><td><a id="l2397"></a><a href="#l2397">2397</a><td> /** @private */<tr><td><a id="l2398"></a><a href="#l2398">2398</a><td> shutdown_: function() {<tr><td><a id="l2399"></a><a href="#l2399">2399</a><td> vlog(1, () =&gt; &#39;Going idle: &#39; + this);<tr><td><a id="l2400"></a><a href="#l2400">2400</a><td> this.cancelHold_();<tr><td><a id="l2401"></a><a href="#l2401">2401</a><td> this.shutdownTask_ = null;<tr><td><a id="l2402"></a><a href="#l2402">2402</a><td> this.emit(promise.ControlFlow.EventType.IDLE);<tr><td><a id="l2403"></a><a href="#l2403">2403</a><td> },<tr><td><a id="l2404"></a><a href="#l2404">2404</a><td><tr><td><a id="l2405"></a><a href="#l2405">2405</a><td> /**<tr><td><a id="l2406"></a><a href="#l2406">2406</a><td> * Cancels the shutdown sequence if it is currently scheduled.<tr><td><a id="l2407"></a><a href="#l2407">2407</a><td> * @private<tr><td><a id="l2408"></a><a href="#l2408">2408</a><td> */<tr><td><a id="l2409"></a><a href="#l2409">2409</a><td> cancelShutdown_: function() {<tr><td><a id="l2410"></a><a href="#l2410">2410</a><td> if (this.shutdownTask_) {<tr><td><a id="l2411"></a><a href="#l2411">2411</a><td> this.shutdownTask_.cancel();<tr><td><a id="l2412"></a><a href="#l2412">2412</a><td> this.shutdownTask_ = null;<tr><td><a id="l2413"></a><a href="#l2413">2413</a><td> }<tr><td><a id="l2414"></a><a href="#l2414">2414</a><td> }<tr><td><a id="l2415"></a><a href="#l2415">2415</a><td>});<tr><td><a id="l2416"></a><a href="#l2416">2416</a><td><tr><td><a id="l2417"></a><a href="#l2417">2417</a><td><tr><td><a id="l2418"></a><a href="#l2418">2418</a><td>/**<tr><td><a id="l2419"></a><a href="#l2419">2419</a><td> * Events that may be emitted by an {@link webdriver.promise.ControlFlow}.<tr><td><a id="l2420"></a><a href="#l2420">2420</a><td> * @enum {string}<tr><td><a id="l2421"></a><a href="#l2421">2421</a><td> */<tr><td><a id="l2422"></a><a href="#l2422">2422</a><td>promise.ControlFlow.EventType = {<tr><td><a id="l2423"></a><a href="#l2423">2423</a><td><tr><td><a id="l2424"></a><a href="#l2424">2424</a><td> /** Emitted when all tasks have been successfully executed. */<tr><td><a id="l2425"></a><a href="#l2425">2425</a><td> IDLE: &#39;idle&#39;,<tr><td><a id="l2426"></a><a href="#l2426">2426</a><td><tr><td><a id="l2427"></a><a href="#l2427">2427</a><td> /** Emitted when a ControlFlow has been reset. */<tr><td><a id="l2428"></a><a href="#l2428">2428</a><td> RESET: &#39;reset&#39;,<tr><td><a id="l2429"></a><a href="#l2429">2429</a><td><tr><td><a id="l2430"></a><a href="#l2430">2430</a><td> /** Emitted whenever a new task has been scheduled. */<tr><td><a id="l2431"></a><a href="#l2431">2431</a><td> SCHEDULE_TASK: &#39;scheduleTask&#39;,<tr><td><a id="l2432"></a><a href="#l2432">2432</a><td><tr><td><a id="l2433"></a><a href="#l2433">2433</a><td> /**<tr><td><a id="l2434"></a><a href="#l2434">2434</a><td> * Emitted whenever a control flow aborts due to an unhandled promise<tr><td><a id="l2435"></a><a href="#l2435">2435</a><td> * rejection. This event will be emitted along with the offending rejection<tr><td><a id="l2436"></a><a href="#l2436">2436</a><td> * reason. Upon emitting this event, the control flow will empty its task<tr><td><a id="l2437"></a><a href="#l2437">2437</a><td> * queue and revert to its initial state.<tr><td><a id="l2438"></a><a href="#l2438">2438</a><td> */<tr><td><a id="l2439"></a><a href="#l2439">2439</a><td> UNCAUGHT_EXCEPTION: &#39;uncaughtException&#39;<tr><td><a id="l2440"></a><a href="#l2440">2440</a><td>};<tr><td><a id="l2441"></a><a href="#l2441">2441</a><td><tr><td><a id="l2442"></a><a href="#l2442">2442</a><td><tr><td><a id="l2443"></a><a href="#l2443">2443</a><td>/**<tr><td><a id="l2444"></a><a href="#l2444">2444</a><td> * Wraps a function to execute as a cancellable micro task.<tr><td><a id="l2445"></a><a href="#l2445">2445</a><td> * @final<tr><td><a id="l2446"></a><a href="#l2446">2446</a><td> */<tr><td><a id="l2447"></a><a href="#l2447">2447</a><td>var MicroTask = goog.defineClass(null, {<tr><td><a id="l2448"></a><a href="#l2448">2448</a><td> /**<tr><td><a id="l2449"></a><a href="#l2449">2449</a><td> * @param {function(this: THIS)} fn The function to run as a micro task.<tr><td><a id="l2450"></a><a href="#l2450">2450</a><td> * @param {THIS=} opt_scope The scope to run the function in.<tr><td><a id="l2451"></a><a href="#l2451">2451</a><td> * @template THIS<tr><td><a id="l2452"></a><a href="#l2452">2452</a><td> */<tr><td><a id="l2453"></a><a href="#l2453">2453</a><td> constructor: function(fn, opt_scope) {<tr><td><a id="l2454"></a><a href="#l2454">2454</a><td> /** @private {boolean} */<tr><td><a id="l2455"></a><a href="#l2455">2455</a><td> this.cancelled_ = false;<tr><td><a id="l2456"></a><a href="#l2456">2456</a><td> asyncRun(function() {<tr><td><a id="l2457"></a><a href="#l2457">2457</a><td> if (!this.cancelled_) {<tr><td><a id="l2458"></a><a href="#l2458">2458</a><td> fn.call(opt_scope);<tr><td><a id="l2459"></a><a href="#l2459">2459</a><td> }<tr><td><a id="l2460"></a><a href="#l2460">2460</a><td> }, this);<tr><td><a id="l2461"></a><a href="#l2461">2461</a><td> },<tr><td><a id="l2462"></a><a href="#l2462">2462</a><td><tr><td><a id="l2463"></a><a href="#l2463">2463</a><td> /**<tr><td><a id="l2464"></a><a href="#l2464">2464</a><td> * Cancels the execution of this task. Note: this will not prevent the task<tr><td><a id="l2465"></a><a href="#l2465">2465</a><td> * timer from firing, just the invocation of the wrapped function.<tr><td><a id="l2466"></a><a href="#l2466">2466</a><td> */<tr><td><a id="l2467"></a><a href="#l2467">2467</a><td> cancel: function() {<tr><td><a id="l2468"></a><a href="#l2468">2468</a><td> this.cancelled_ = true;<tr><td><a id="l2469"></a><a href="#l2469">2469</a><td> }<tr><td><a id="l2470"></a><a href="#l2470">2470</a><td>});<tr><td><a id="l2471"></a><a href="#l2471">2471</a><td><tr><td><a id="l2472"></a><a href="#l2472">2472</a><td><tr><td><a id="l2473"></a><a href="#l2473">2473</a><td>/**<tr><td><a id="l2474"></a><a href="#l2474">2474</a><td> * A task to be executed by a {@link webdriver.promise.ControlFlow}.<tr><td><a id="l2475"></a><a href="#l2475">2475</a><td> *<tr><td><a id="l2476"></a><a href="#l2476">2476</a><td> * @final<tr><td><a id="l2477"></a><a href="#l2477">2477</a><td> */<tr><td><a id="l2478"></a><a href="#l2478">2478</a><td>var Task = goog.defineClass(promise.Deferred, {<tr><td><a id="l2479"></a><a href="#l2479">2479</a><td> /**<tr><td><a id="l2480"></a><a href="#l2480">2480</a><td> * @param {!promise.ControlFlow} flow The flow this instances belongs<tr><td><a id="l2481"></a><a href="#l2481">2481</a><td> * to.<tr><td><a id="l2482"></a><a href="#l2482">2482</a><td> * @param {function(): (T|!promise.Promise&lt;T&gt;)} fn The function to<tr><td><a id="l2483"></a><a href="#l2483">2483</a><td> * call when the task executes. If it returns a<tr><td><a id="l2484"></a><a href="#l2484">2484</a><td> * {@link webdriver.promise.Promise}, the flow will wait for it to be<tr><td><a id="l2485"></a><a href="#l2485">2485</a><td> * resolved before starting the next task.<tr><td><a id="l2486"></a><a href="#l2486">2486</a><td> * @param {string} description A description of the task for debugging.<tr><td><a id="l2487"></a><a href="#l2487">2487</a><td> * @param {{name: string, top: !Function}=} opt_stackOptions Options to use<tr><td><a id="l2488"></a><a href="#l2488">2488</a><td> * when capturing the stacktrace for when this task was created.<tr><td><a id="l2489"></a><a href="#l2489">2489</a><td> * @constructor<tr><td><a id="l2490"></a><a href="#l2490">2490</a><td> * @extends {promise.Deferred&lt;T&gt;}<tr><td><a id="l2491"></a><a href="#l2491">2491</a><td> * @template T<tr><td><a id="l2492"></a><a href="#l2492">2492</a><td> */<tr><td><a id="l2493"></a><a href="#l2493">2493</a><td> constructor: function(flow, fn, description, opt_stackOptions) {<tr><td><a id="l2494"></a><a href="#l2494">2494</a><td> Task.base(this, &#39;constructor&#39;, flow);<tr><td><a id="l2495"></a><a href="#l2495">2495</a><td><tr><td><a id="l2496"></a><a href="#l2496">2496</a><td> /** @type {function(): (T|!promise.Promise&lt;T&gt;)} */<tr><td><a id="l2497"></a><a href="#l2497">2497</a><td> this.execute = fn;<tr><td><a id="l2498"></a><a href="#l2498">2498</a><td><tr><td><a id="l2499"></a><a href="#l2499">2499</a><td> /** @type {string} */<tr><td><a id="l2500"></a><a href="#l2500">2500</a><td> this.description = description;<tr><td><a id="l2501"></a><a href="#l2501">2501</a><td><tr><td><a id="l2502"></a><a href="#l2502">2502</a><td> /** @type {TaskQueue} */<tr><td><a id="l2503"></a><a href="#l2503">2503</a><td> this.queue = null;<tr><td><a id="l2504"></a><a href="#l2504">2504</a><td><tr><td><a id="l2505"></a><a href="#l2505">2505</a><td> /**<tr><td><a id="l2506"></a><a href="#l2506">2506</a><td> * Whether this task is considered block. A blocked task may be registered<tr><td><a id="l2507"></a><a href="#l2507">2507</a><td> * in a task queue, but will be dropped if it is still blocked when it<tr><td><a id="l2508"></a><a href="#l2508">2508</a><td> * reaches the front of the queue. A dropped task may always be rescheduled.<tr><td><a id="l2509"></a><a href="#l2509">2509</a><td> *<tr><td><a id="l2510"></a><a href="#l2510">2510</a><td> * Blocked tasks are used when a callback is attached to an unsettled<tr><td><a id="l2511"></a><a href="#l2511">2511</a><td> * promise to reserve a spot in line (in a manner of speaking). If the<tr><td><a id="l2512"></a><a href="#l2512">2512</a><td> * promise is not settled before the callback reaches the front of the<tr><td><a id="l2513"></a><a href="#l2513">2513</a><td> * of the queue, it will be dropped. Once the promise is settled, the<tr><td><a id="l2514"></a><a href="#l2514">2514</a><td> * dropped task will be rescheduled as an interrupt on the currently task<tr><td><a id="l2515"></a><a href="#l2515">2515</a><td> * queue.<tr><td><a id="l2516"></a><a href="#l2516">2516</a><td> *<tr><td><a id="l2517"></a><a href="#l2517">2517</a><td> * @type {boolean}<tr><td><a id="l2518"></a><a href="#l2518">2518</a><td> */<tr><td><a id="l2519"></a><a href="#l2519">2519</a><td> this.blocked = false;<tr><td><a id="l2520"></a><a href="#l2520">2520</a><td><tr><td><a id="l2521"></a><a href="#l2521">2521</a><td> if (opt_stackOptions) {<tr><td><a id="l2522"></a><a href="#l2522">2522</a><td> this.promise.stack_ = promise.captureStackTrace(<tr><td><a id="l2523"></a><a href="#l2523">2523</a><td> opt_stackOptions.name, this.description, opt_stackOptions.top);<tr><td><a id="l2524"></a><a href="#l2524">2524</a><td> }<tr><td><a id="l2525"></a><a href="#l2525">2525</a><td> },<tr><td><a id="l2526"></a><a href="#l2526">2526</a><td><tr><td><a id="l2527"></a><a href="#l2527">2527</a><td> /** @override */<tr><td><a id="l2528"></a><a href="#l2528">2528</a><td> toString: function() {<tr><td><a id="l2529"></a><a href="#l2529">2529</a><td> return &#39;Task::&#39; + goog.getUid(this) + &#39;&lt;&#39; + this.description + &#39;&gt;&#39;;<tr><td><a id="l2530"></a><a href="#l2530">2530</a><td> }<tr><td><a id="l2531"></a><a href="#l2531">2531</a><td>});<tr><td><a id="l2532"></a><a href="#l2532">2532</a><td><tr><td><a id="l2533"></a><a href="#l2533">2533</a><td><tr><td><a id="l2534"></a><a href="#l2534">2534</a><td>/** @enum {string} */<tr><td><a id="l2535"></a><a href="#l2535">2535</a><td>var TaskQueueState = {<tr><td><a id="l2536"></a><a href="#l2536">2536</a><td> NEW: &#39;new&#39;,<tr><td><a id="l2537"></a><a href="#l2537">2537</a><td> STARTED: &#39;started&#39;,<tr><td><a id="l2538"></a><a href="#l2538">2538</a><td> FINISHED: &#39;finished&#39;<tr><td><a id="l2539"></a><a href="#l2539">2539</a><td>};<tr><td><a id="l2540"></a><a href="#l2540">2540</a><td><tr><td><a id="l2541"></a><a href="#l2541">2541</a><td><tr><td><a id="l2542"></a><a href="#l2542">2542</a><td>/**<tr><td><a id="l2543"></a><a href="#l2543">2543</a><td> * @final<tr><td><a id="l2544"></a><a href="#l2544">2544</a><td> */<tr><td><a id="l2545"></a><a href="#l2545">2545</a><td>var TaskQueue = goog.defineClass(EventEmitter, {<tr><td><a id="l2546"></a><a href="#l2546">2546</a><td> /** @param {!promise.ControlFlow} flow . */<tr><td><a id="l2547"></a><a href="#l2547">2547</a><td> constructor: function(flow) {<tr><td><a id="l2548"></a><a href="#l2548">2548</a><td> TaskQueue.base(this, &#39;constructor&#39;);<tr><td><a id="l2549"></a><a href="#l2549">2549</a><td> goog.getUid(this);<tr><td><a id="l2550"></a><a href="#l2550">2550</a><td><tr><td><a id="l2551"></a><a href="#l2551">2551</a><td> /** @private {string} */<tr><td><a id="l2552"></a><a href="#l2552">2552</a><td> this.name_ = &#39;TaskQueue::&#39; + goog.getUid(this);<tr><td><a id="l2553"></a><a href="#l2553">2553</a><td><tr><td><a id="l2554"></a><a href="#l2554">2554</a><td> /** @private {!promise.ControlFlow} */<tr><td><a id="l2555"></a><a href="#l2555">2555</a><td> this.flow_ = flow;<tr><td><a id="l2556"></a><a href="#l2556">2556</a><td><tr><td><a id="l2557"></a><a href="#l2557">2557</a><td> /** @private {!Array&lt;!Task&gt;} */<tr><td><a id="l2558"></a><a href="#l2558">2558</a><td> this.tasks_ = [];<tr><td><a id="l2559"></a><a href="#l2559">2559</a><td><tr><td><a id="l2560"></a><a href="#l2560">2560</a><td> /** @private {Array&lt;!Task&gt;} */<tr><td><a id="l2561"></a><a href="#l2561">2561</a><td> this.interrupts_ = null;<tr><td><a id="l2562"></a><a href="#l2562">2562</a><td><tr><td><a id="l2563"></a><a href="#l2563">2563</a><td> /** @private {({task: !Task, q: !TaskQueue}|null)} */<tr><td><a id="l2564"></a><a href="#l2564">2564</a><td> this.pending_ = null;<tr><td><a id="l2565"></a><a href="#l2565">2565</a><td><tr><td><a id="l2566"></a><a href="#l2566">2566</a><td> /** @private {TaskQueueState} */<tr><td><a id="l2567"></a><a href="#l2567">2567</a><td> this.state_ = TaskQueueState.NEW;<tr><td><a id="l2568"></a><a href="#l2568">2568</a><td><tr><td><a id="l2569"></a><a href="#l2569">2569</a><td> /** @private {!Set&lt;!webdriver.promise.Promise&gt;} */<tr><td><a id="l2570"></a><a href="#l2570">2570</a><td> this.unhandledRejections_ = new Set();<tr><td><a id="l2571"></a><a href="#l2571">2571</a><td> },<tr><td><a id="l2572"></a><a href="#l2572">2572</a><td><tr><td><a id="l2573"></a><a href="#l2573">2573</a><td> /** @override */<tr><td><a id="l2574"></a><a href="#l2574">2574</a><td> toString: function() {<tr><td><a id="l2575"></a><a href="#l2575">2575</a><td> return &#39;TaskQueue::&#39; + goog.getUid(this);<tr><td><a id="l2576"></a><a href="#l2576">2576</a><td> },<tr><td><a id="l2577"></a><a href="#l2577">2577</a><td><tr><td><a id="l2578"></a><a href="#l2578">2578</a><td> /**<tr><td><a id="l2579"></a><a href="#l2579">2579</a><td> * @param {!webdriver.promise.Promise} promise .<tr><td><a id="l2580"></a><a href="#l2580">2580</a><td> */<tr><td><a id="l2581"></a><a href="#l2581">2581</a><td> addUnhandledRejection: function(promise) {<tr><td><a id="l2582"></a><a href="#l2582">2582</a><td> // TODO: node 4.0.0+<tr><td><a id="l2583"></a><a href="#l2583">2583</a><td> vlog(2, () =&gt; this + &#39; registering unhandled rejection: &#39; + promise, this);<tr><td><a id="l2584"></a><a href="#l2584">2584</a><td> this.unhandledRejections_.add(promise);<tr><td><a id="l2585"></a><a href="#l2585">2585</a><td> },<tr><td><a id="l2586"></a><a href="#l2586">2586</a><td><tr><td><a id="l2587"></a><a href="#l2587">2587</a><td> /**<tr><td><a id="l2588"></a><a href="#l2588">2588</a><td> * @param {!webdriver.promise.Promise} promise .<tr><td><a id="l2589"></a><a href="#l2589">2589</a><td> */<tr><td><a id="l2590"></a><a href="#l2590">2590</a><td> clearUnhandledRejection: function(promise) {<tr><td><a id="l2591"></a><a href="#l2591">2591</a><td> var deleted = this.unhandledRejections_.delete(promise);<tr><td><a id="l2592"></a><a href="#l2592">2592</a><td> if (deleted) {<tr><td><a id="l2593"></a><a href="#l2593">2593</a><td> // TODO: node 4.0.0+<tr><td><a id="l2594"></a><a href="#l2594">2594</a><td> vlog(2, () =&gt; this + &#39; clearing unhandled rejection: &#39; + promise, this);<tr><td><a id="l2595"></a><a href="#l2595">2595</a><td> }<tr><td><a id="l2596"></a><a href="#l2596">2596</a><td> },<tr><td><a id="l2597"></a><a href="#l2597">2597</a><td><tr><td><a id="l2598"></a><a href="#l2598">2598</a><td> /**<tr><td><a id="l2599"></a><a href="#l2599">2599</a><td> * Enqueues a new task for execution.<tr><td><a id="l2600"></a><a href="#l2600">2600</a><td> * @param {!Task} task The task to enqueue.<tr><td><a id="l2601"></a><a href="#l2601">2601</a><td> * @throws {Error} If this instance has already started execution.<tr><td><a id="l2602"></a><a href="#l2602">2602</a><td> */<tr><td><a id="l2603"></a><a href="#l2603">2603</a><td> enqueue: function(task) {<tr><td><a id="l2604"></a><a href="#l2604">2604</a><td> if (this.state_ !== TaskQueueState.NEW) {<tr><td><a id="l2605"></a><a href="#l2605">2605</a><td> throw Error(&#39;TaskQueue has started: &#39; + this);<tr><td><a id="l2606"></a><a href="#l2606">2606</a><td> }<tr><td><a id="l2607"></a><a href="#l2607">2607</a><td><tr><td><a id="l2608"></a><a href="#l2608">2608</a><td> if (task.queue) {<tr><td><a id="l2609"></a><a href="#l2609">2609</a><td> throw Error(&#39;Task is already scheduled in another queue&#39;);<tr><td><a id="l2610"></a><a href="#l2610">2610</a><td> }<tr><td><a id="l2611"></a><a href="#l2611">2611</a><td><tr><td><a id="l2612"></a><a href="#l2612">2612</a><td> this.tasks_.push(task);<tr><td><a id="l2613"></a><a href="#l2613">2613</a><td> task.queue = this;<tr><td><a id="l2614"></a><a href="#l2614">2614</a><td> task.promise[CANCEL_HANDLER_SYMBOL] =<tr><td><a id="l2615"></a><a href="#l2615">2615</a><td> this.onTaskCancelled_.bind(this, task);<tr><td><a id="l2616"></a><a href="#l2616">2616</a><td><tr><td><a id="l2617"></a><a href="#l2617">2617</a><td> vlog(1, () =&gt; this + &#39;.enqueue(&#39; + task + &#39;)&#39;, this);<tr><td><a id="l2618"></a><a href="#l2618">2618</a><td> vlog(2, () =&gt; this.flow_.toString(), this);<tr><td><a id="l2619"></a><a href="#l2619">2619</a><td> },<tr><td><a id="l2620"></a><a href="#l2620">2620</a><td><tr><td><a id="l2621"></a><a href="#l2621">2621</a><td> /**<tr><td><a id="l2622"></a><a href="#l2622">2622</a><td> * Schedules the callbacks registered on the given promise in this queue.<tr><td><a id="l2623"></a><a href="#l2623">2623</a><td> *<tr><td><a id="l2624"></a><a href="#l2624">2624</a><td> * @param {!promise.Promise} promise the promise whose callbacks should be<tr><td><a id="l2625"></a><a href="#l2625">2625</a><td> * registered as interrupts in this task queue.<tr><td><a id="l2626"></a><a href="#l2626">2626</a><td> * @throws {Error} if this queue has already finished.<tr><td><a id="l2627"></a><a href="#l2627">2627</a><td> */<tr><td><a id="l2628"></a><a href="#l2628">2628</a><td> scheduleCallbacks: function(promise) {<tr><td><a id="l2629"></a><a href="#l2629">2629</a><td> if (this.state_ === TaskQueueState.FINISHED) {<tr><td><a id="l2630"></a><a href="#l2630">2630</a><td> throw new Error(&#39;cannot interrupt a finished q(&#39; + this + &#39;)&#39;);<tr><td><a id="l2631"></a><a href="#l2631">2631</a><td> }<tr><td><a id="l2632"></a><a href="#l2632">2632</a><td><tr><td><a id="l2633"></a><a href="#l2633">2633</a><td> if (this.pending_ &amp;&amp; this.pending_.task.promise === promise) {<tr><td><a id="l2634"></a><a href="#l2634">2634</a><td> this.pending_.task.promise.queue_ = null;<tr><td><a id="l2635"></a><a href="#l2635">2635</a><td> this.pending_ = null;<tr><td><a id="l2636"></a><a href="#l2636">2636</a><td> asyncRun(this.executeNext_, this);<tr><td><a id="l2637"></a><a href="#l2637">2637</a><td> }<tr><td><a id="l2638"></a><a href="#l2638">2638</a><td><tr><td><a id="l2639"></a><a href="#l2639">2639</a><td> if (!promise.callbacks_) {<tr><td><a id="l2640"></a><a href="#l2640">2640</a><td> return;<tr><td><a id="l2641"></a><a href="#l2641">2641</a><td> }<tr><td><a id="l2642"></a><a href="#l2642">2642</a><td> promise.callbacks_.forEach(function(cb) {<tr><td><a id="l2643"></a><a href="#l2643">2643</a><td> cb.blocked = false;<tr><td><a id="l2644"></a><a href="#l2644">2644</a><td> if (cb.queue) {<tr><td><a id="l2645"></a><a href="#l2645">2645</a><td> return;<tr><td><a id="l2646"></a><a href="#l2646">2646</a><td> }<tr><td><a id="l2647"></a><a href="#l2647">2647</a><td><tr><td><a id="l2648"></a><a href="#l2648">2648</a><td> cb.promise[CANCEL_HANDLER_SYMBOL] = this.onTaskCancelled_.bind(this, cb);<tr><td><a id="l2649"></a><a href="#l2649">2649</a><td><tr><td><a id="l2650"></a><a href="#l2650">2650</a><td> if (cb.queue === this &amp;&amp; this.tasks_.indexOf(cb) !== -1) {<tr><td><a id="l2651"></a><a href="#l2651">2651</a><td> return;<tr><td><a id="l2652"></a><a href="#l2652">2652</a><td> }<tr><td><a id="l2653"></a><a href="#l2653">2653</a><td><tr><td><a id="l2654"></a><a href="#l2654">2654</a><td> if (cb.queue) {<tr><td><a id="l2655"></a><a href="#l2655">2655</a><td> cb.queue.dropTask_(cb);<tr><td><a id="l2656"></a><a href="#l2656">2656</a><td> }<tr><td><a id="l2657"></a><a href="#l2657">2657</a><td><tr><td><a id="l2658"></a><a href="#l2658">2658</a><td> cb.queue = this;<tr><td><a id="l2659"></a><a href="#l2659">2659</a><td> if (!this.interrupts_) {<tr><td><a id="l2660"></a><a href="#l2660">2660</a><td> this.interrupts_ = [];<tr><td><a id="l2661"></a><a href="#l2661">2661</a><td> }<tr><td><a id="l2662"></a><a href="#l2662">2662</a><td> this.interrupts_.push(cb);<tr><td><a id="l2663"></a><a href="#l2663">2663</a><td> }, this);<tr><td><a id="l2664"></a><a href="#l2664">2664</a><td> promise.callbacks_ = null;<tr><td><a id="l2665"></a><a href="#l2665">2665</a><td> vlog(2, () =&gt; this + &#39; interrupted\n&#39; + this.flow_, this);<tr><td><a id="l2666"></a><a href="#l2666">2666</a><td> },<tr><td><a id="l2667"></a><a href="#l2667">2667</a><td><tr><td><a id="l2668"></a><a href="#l2668">2668</a><td> /**<tr><td><a id="l2669"></a><a href="#l2669">2669</a><td> * Starts executing tasks in this queue. Once called, no further tasks may<tr><td><a id="l2670"></a><a href="#l2670">2670</a><td> * be {@linkplain #enqueue() enqueued} with this instance.<tr><td><a id="l2671"></a><a href="#l2671">2671</a><td> *<tr><td><a id="l2672"></a><a href="#l2672">2672</a><td> * @throws {Error} if this queue has already been started.<tr><td><a id="l2673"></a><a href="#l2673">2673</a><td> */<tr><td><a id="l2674"></a><a href="#l2674">2674</a><td> start: function() {<tr><td><a id="l2675"></a><a href="#l2675">2675</a><td> if (this.state_ !== TaskQueueState.NEW) {<tr><td><a id="l2676"></a><a href="#l2676">2676</a><td> throw new Error(&#39;TaskQueue has already started&#39;);<tr><td><a id="l2677"></a><a href="#l2677">2677</a><td> }<tr><td><a id="l2678"></a><a href="#l2678">2678</a><td> // Always asynchronously execute next, even if there doesn&#39;t look like<tr><td><a id="l2679"></a><a href="#l2679">2679</a><td> // there is anything in the queue. This will catch pending unhandled<tr><td><a id="l2680"></a><a href="#l2680">2680</a><td> // rejections that were registered before start was called.<tr><td><a id="l2681"></a><a href="#l2681">2681</a><td> asyncRun(this.executeNext_, this);<tr><td><a id="l2682"></a><a href="#l2682">2682</a><td> },<tr><td><a id="l2683"></a><a href="#l2683">2683</a><td><tr><td><a id="l2684"></a><a href="#l2684">2684</a><td> /**<tr><td><a id="l2685"></a><a href="#l2685">2685</a><td> * Aborts this task queue. If there are any scheduled tasks, they are silently<tr><td><a id="l2686"></a><a href="#l2686">2686</a><td> * cancelled and discarded (their callbacks will never fire). If this queue<tr><td><a id="l2687"></a><a href="#l2687">2687</a><td> * has a _pending_ task, the abortion error is used to cancel that task.<tr><td><a id="l2688"></a><a href="#l2688">2688</a><td> * Otherwise, this queue will emit an error event.<tr><td><a id="l2689"></a><a href="#l2689">2689</a><td> *<tr><td><a id="l2690"></a><a href="#l2690">2690</a><td> * @param {*} error The abortion reason.<tr><td><a id="l2691"></a><a href="#l2691">2691</a><td> * @private<tr><td><a id="l2692"></a><a href="#l2692">2692</a><td> */<tr><td><a id="l2693"></a><a href="#l2693">2693</a><td> abort_: function(error) {<tr><td><a id="l2694"></a><a href="#l2694">2694</a><td> var cancellation;<tr><td><a id="l2695"></a><a href="#l2695">2695</a><td><tr><td><a id="l2696"></a><a href="#l2696">2696</a><td> if (error instanceof FlowResetError) {<tr><td><a id="l2697"></a><a href="#l2697">2697</a><td> cancellation = error;<tr><td><a id="l2698"></a><a href="#l2698">2698</a><td> } else {<tr><td><a id="l2699"></a><a href="#l2699">2699</a><td> cancellation = new DiscardedTaskError(error);<tr><td><a id="l2700"></a><a href="#l2700">2700</a><td> }<tr><td><a id="l2701"></a><a href="#l2701">2701</a><td><tr><td><a id="l2702"></a><a href="#l2702">2702</a><td> if (this.interrupts_ &amp;&amp; this.interrupts_.length) {<tr><td><a id="l2703"></a><a href="#l2703">2703</a><td> this.interrupts_.forEach((t) =&gt; t.reject(cancellation));<tr><td><a id="l2704"></a><a href="#l2704">2704</a><td> this.interrupts_ = [];<tr><td><a id="l2705"></a><a href="#l2705">2705</a><td> }<tr><td><a id="l2706"></a><a href="#l2706">2706</a><td><tr><td><a id="l2707"></a><a href="#l2707">2707</a><td> if (this.tasks_ &amp;&amp; this.tasks_.length) {<tr><td><a id="l2708"></a><a href="#l2708">2708</a><td> this.tasks_.forEach((t) =&gt; t.reject(cancellation));<tr><td><a id="l2709"></a><a href="#l2709">2709</a><td> this.tasks_ = [];<tr><td><a id="l2710"></a><a href="#l2710">2710</a><td> }<tr><td><a id="l2711"></a><a href="#l2711">2711</a><td><tr><td><a id="l2712"></a><a href="#l2712">2712</a><td> if (this.pending_) {<tr><td><a id="l2713"></a><a href="#l2713">2713</a><td> vlog(2, () =&gt; this + &#39;.abort(); cancelling pending task&#39;, this);<tr><td><a id="l2714"></a><a href="#l2714">2714</a><td> this.pending_.task.cancel(<tr><td><a id="l2715"></a><a href="#l2715">2715</a><td> /** @type {!webdriver.promise.CancellationError} */(error));<tr><td><a id="l2716"></a><a href="#l2716">2716</a><td><tr><td><a id="l2717"></a><a href="#l2717">2717</a><td> } else {<tr><td><a id="l2718"></a><a href="#l2718">2718</a><td> vlog(2, () =&gt; this + &#39;.abort(); emitting error event&#39;, this);<tr><td><a id="l2719"></a><a href="#l2719">2719</a><td> this.emit(&#39;error&#39;, error, this);<tr><td><a id="l2720"></a><a href="#l2720">2720</a><td> }<tr><td><a id="l2721"></a><a href="#l2721">2721</a><td> },<tr><td><a id="l2722"></a><a href="#l2722">2722</a><td><tr><td><a id="l2723"></a><a href="#l2723">2723</a><td> /** @private */<tr><td><a id="l2724"></a><a href="#l2724">2724</a><td> executeNext_: function() {<tr><td><a id="l2725"></a><a href="#l2725">2725</a><td> if (this.state_ === TaskQueueState.FINISHED) {<tr><td><a id="l2726"></a><a href="#l2726">2726</a><td> return;<tr><td><a id="l2727"></a><a href="#l2727">2727</a><td> }<tr><td><a id="l2728"></a><a href="#l2728">2728</a><td> this.state_ = TaskQueueState.STARTED;<tr><td><a id="l2729"></a><a href="#l2729">2729</a><td><tr><td><a id="l2730"></a><a href="#l2730">2730</a><td> if (this.pending_ != null || this.processUnhandledRejections_()) {<tr><td><a id="l2731"></a><a href="#l2731">2731</a><td> return;<tr><td><a id="l2732"></a><a href="#l2732">2732</a><td> }<tr><td><a id="l2733"></a><a href="#l2733">2733</a><td><tr><td><a id="l2734"></a><a href="#l2734">2734</a><td> var task;<tr><td><a id="l2735"></a><a href="#l2735">2735</a><td> do {<tr><td><a id="l2736"></a><a href="#l2736">2736</a><td> task = this.getNextTask_();<tr><td><a id="l2737"></a><a href="#l2737">2737</a><td> } while (task &amp;&amp; !task.promise.isPending());<tr><td><a id="l2738"></a><a href="#l2738">2738</a><td><tr><td><a id="l2739"></a><a href="#l2739">2739</a><td> if (!task) {<tr><td><a id="l2740"></a><a href="#l2740">2740</a><td> this.state_ = TaskQueueState.FINISHED;<tr><td><a id="l2741"></a><a href="#l2741">2741</a><td> this.tasks_ = [];<tr><td><a id="l2742"></a><a href="#l2742">2742</a><td> this.interrupts_ = null;<tr><td><a id="l2743"></a><a href="#l2743">2743</a><td> vlog(2, () =&gt; this + &#39;.emit(end)&#39;, this);<tr><td><a id="l2744"></a><a href="#l2744">2744</a><td> this.emit(&#39;end&#39;, this);<tr><td><a id="l2745"></a><a href="#l2745">2745</a><td> return;<tr><td><a id="l2746"></a><a href="#l2746">2746</a><td> }<tr><td><a id="l2747"></a><a href="#l2747">2747</a><td><tr><td><a id="l2748"></a><a href="#l2748">2748</a><td> var self = this;<tr><td><a id="l2749"></a><a href="#l2749">2749</a><td> var subQ = new TaskQueue(this.flow_);<tr><td><a id="l2750"></a><a href="#l2750">2750</a><td> subQ.once(&#39;end&#39;, () =&gt; self.onTaskComplete_(result))<tr><td><a id="l2751"></a><a href="#l2751">2751</a><td> .once(&#39;error&#39;, (e) =&gt; self.onTaskFailure_(result, e));<tr><td><a id="l2752"></a><a href="#l2752">2752</a><td> vlog(2, () =&gt; self + &#39; created &#39; + subQ + &#39; for &#39; + task);<tr><td><a id="l2753"></a><a href="#l2753">2753</a><td><tr><td><a id="l2754"></a><a href="#l2754">2754</a><td> var result = undefined;<tr><td><a id="l2755"></a><a href="#l2755">2755</a><td> try {<tr><td><a id="l2756"></a><a href="#l2756">2756</a><td> this.pending_ = {task: task, q: subQ};<tr><td><a id="l2757"></a><a href="#l2757">2757</a><td> task.promise.queue_ = this;<tr><td><a id="l2758"></a><a href="#l2758">2758</a><td> result = subQ.execute_(task.execute);<tr><td><a id="l2759"></a><a href="#l2759">2759</a><td> subQ.start();<tr><td><a id="l2760"></a><a href="#l2760">2760</a><td> } catch (ex) {<tr><td><a id="l2761"></a><a href="#l2761">2761</a><td> subQ.abort_(ex);<tr><td><a id="l2762"></a><a href="#l2762">2762</a><td> }<tr><td><a id="l2763"></a><a href="#l2763">2763</a><td> },<tr><td><a id="l2764"></a><a href="#l2764">2764</a><td><tr><td><a id="l2765"></a><a href="#l2765">2765</a><td><tr><td><a id="l2766"></a><a href="#l2766">2766</a><td> /**<tr><td><a id="l2767"></a><a href="#l2767">2767</a><td> * @param {!Function} fn .<tr><td><a id="l2768"></a><a href="#l2768">2768</a><td> * @return {T} .<tr><td><a id="l2769"></a><a href="#l2769">2769</a><td> * @template T<tr><td><a id="l2770"></a><a href="#l2770">2770</a><td> * @private<tr><td><a id="l2771"></a><a href="#l2771">2771</a><td> */<tr><td><a id="l2772"></a><a href="#l2772">2772</a><td> execute_: function(fn) {<tr><td><a id="l2773"></a><a href="#l2773">2773</a><td> try {<tr><td><a id="l2774"></a><a href="#l2774">2774</a><td> activeFlows.push(this.flow_);<tr><td><a id="l2775"></a><a href="#l2775">2775</a><td> this.flow_.activeQueue_ = this;<tr><td><a id="l2776"></a><a href="#l2776">2776</a><td> return fn();<tr><td><a id="l2777"></a><a href="#l2777">2777</a><td> } finally {<tr><td><a id="l2778"></a><a href="#l2778">2778</a><td> this.flow_.activeQueue_ = null;<tr><td><a id="l2779"></a><a href="#l2779">2779</a><td> activeFlows.pop();<tr><td><a id="l2780"></a><a href="#l2780">2780</a><td> }<tr><td><a id="l2781"></a><a href="#l2781">2781</a><td> },<tr><td><a id="l2782"></a><a href="#l2782">2782</a><td><tr><td><a id="l2783"></a><a href="#l2783">2783</a><td> /**<tr><td><a id="l2784"></a><a href="#l2784">2784</a><td> * Process any unhandled rejections registered with this task queue. If there<tr><td><a id="l2785"></a><a href="#l2785">2785</a><td> * is a rejection, this queue will be aborted with the rejection error. If<tr><td><a id="l2786"></a><a href="#l2786">2786</a><td> * there are multiple rejections registered, this queue will be aborted with<tr><td><a id="l2787"></a><a href="#l2787">2787</a><td> * a {@link promise.MultipleUnhandledRejectionError}.<tr><td><a id="l2788"></a><a href="#l2788">2788</a><td> * @return {boolean} whether there was an unhandled rejection.<tr><td><a id="l2789"></a><a href="#l2789">2789</a><td> * @private<tr><td><a id="l2790"></a><a href="#l2790">2790</a><td> */<tr><td><a id="l2791"></a><a href="#l2791">2791</a><td> processUnhandledRejections_: function() {<tr><td><a id="l2792"></a><a href="#l2792">2792</a><td> if (!this.unhandledRejections_.size) {<tr><td><a id="l2793"></a><a href="#l2793">2793</a><td> return false;<tr><td><a id="l2794"></a><a href="#l2794">2794</a><td> }<tr><td><a id="l2795"></a><a href="#l2795">2795</a><td><tr><td><a id="l2796"></a><a href="#l2796">2796</a><td> var errors = new Set();<tr><td><a id="l2797"></a><a href="#l2797">2797</a><td> for (var rejection of this.unhandledRejections_) {<tr><td><a id="l2798"></a><a href="#l2798">2798</a><td> errors.add(rejection.value_);<tr><td><a id="l2799"></a><a href="#l2799">2799</a><td> }<tr><td><a id="l2800"></a><a href="#l2800">2800</a><td> this.unhandledRejections_.clear();<tr><td><a id="l2801"></a><a href="#l2801">2801</a><td><tr><td><a id="l2802"></a><a href="#l2802">2802</a><td> var errorToReport = errors.size === 1<tr><td><a id="l2803"></a><a href="#l2803">2803</a><td> ? errors.values().next().value<tr><td><a id="l2804"></a><a href="#l2804">2804</a><td> : new promise.MultipleUnhandledRejectionError(errors);<tr><td><a id="l2805"></a><a href="#l2805">2805</a><td><tr><td><a id="l2806"></a><a href="#l2806">2806</a><td> vlog(1, () =&gt; this + &#39; aborting due to unhandled rejections&#39;, this);<tr><td><a id="l2807"></a><a href="#l2807">2807</a><td> if (this.flow_.propagateUnhandledRejections_) {<tr><td><a id="l2808"></a><a href="#l2808">2808</a><td> this.abort_(errorToReport);<tr><td><a id="l2809"></a><a href="#l2809">2809</a><td> return true;<tr><td><a id="l2810"></a><a href="#l2810">2810</a><td> } else {<tr><td><a id="l2811"></a><a href="#l2811">2811</a><td> vlog(1, &#39;error propagation disabled; reporting to control flow&#39;);<tr><td><a id="l2812"></a><a href="#l2812">2812</a><td> this.flow_.reportUncaughtException_(errorToReport);<tr><td><a id="l2813"></a><a href="#l2813">2813</a><td> return false;<tr><td><a id="l2814"></a><a href="#l2814">2814</a><td> }<tr><td><a id="l2815"></a><a href="#l2815">2815</a><td> },<tr><td><a id="l2816"></a><a href="#l2816">2816</a><td><tr><td><a id="l2817"></a><a href="#l2817">2817</a><td> /**<tr><td><a id="l2818"></a><a href="#l2818">2818</a><td> * @param {!Task} task The task to drop.<tr><td><a id="l2819"></a><a href="#l2819">2819</a><td> * @private<tr><td><a id="l2820"></a><a href="#l2820">2820</a><td> */<tr><td><a id="l2821"></a><a href="#l2821">2821</a><td> dropTask_: function(task) {<tr><td><a id="l2822"></a><a href="#l2822">2822</a><td> var index;<tr><td><a id="l2823"></a><a href="#l2823">2823</a><td> if (this.interrupts_) {<tr><td><a id="l2824"></a><a href="#l2824">2824</a><td> index = this.interrupts_.indexOf(task);<tr><td><a id="l2825"></a><a href="#l2825">2825</a><td> if (index != -1) {<tr><td><a id="l2826"></a><a href="#l2826">2826</a><td> task.queue = null;<tr><td><a id="l2827"></a><a href="#l2827">2827</a><td> this.interrupts_.splice(index, 1);<tr><td><a id="l2828"></a><a href="#l2828">2828</a><td> return;<tr><td><a id="l2829"></a><a href="#l2829">2829</a><td> }<tr><td><a id="l2830"></a><a href="#l2830">2830</a><td> }<tr><td><a id="l2831"></a><a href="#l2831">2831</a><td><tr><td><a id="l2832"></a><a href="#l2832">2832</a><td> index = this.tasks_.indexOf(task);<tr><td><a id="l2833"></a><a href="#l2833">2833</a><td> if (index != -1) {<tr><td><a id="l2834"></a><a href="#l2834">2834</a><td> task.queue = null;<tr><td><a id="l2835"></a><a href="#l2835">2835</a><td> this.tasks_.splice(index, 1);<tr><td><a id="l2836"></a><a href="#l2836">2836</a><td> }<tr><td><a id="l2837"></a><a href="#l2837">2837</a><td> },<tr><td><a id="l2838"></a><a href="#l2838">2838</a><td><tr><td><a id="l2839"></a><a href="#l2839">2839</a><td> /**<tr><td><a id="l2840"></a><a href="#l2840">2840</a><td> * @param {!Task} task The task that was cancelled.<tr><td><a id="l2841"></a><a href="#l2841">2841</a><td> * @param {!promise.CancellationError} reason The cancellation reason.<tr><td><a id="l2842"></a><a href="#l2842">2842</a><td> * @private<tr><td><a id="l2843"></a><a href="#l2843">2843</a><td> */<tr><td><a id="l2844"></a><a href="#l2844">2844</a><td> onTaskCancelled_: function(task, reason) {<tr><td><a id="l2845"></a><a href="#l2845">2845</a><td> if (this.pending_ &amp;&amp; this.pending_.task === task) {<tr><td><a id="l2846"></a><a href="#l2846">2846</a><td> this.pending_.q.abort_(reason);<tr><td><a id="l2847"></a><a href="#l2847">2847</a><td> } else {<tr><td><a id="l2848"></a><a href="#l2848">2848</a><td> this.dropTask_(task);<tr><td><a id="l2849"></a><a href="#l2849">2849</a><td> }<tr><td><a id="l2850"></a><a href="#l2850">2850</a><td> },<tr><td><a id="l2851"></a><a href="#l2851">2851</a><td><tr><td><a id="l2852"></a><a href="#l2852">2852</a><td> /**<tr><td><a id="l2853"></a><a href="#l2853">2853</a><td> * @param {*} value the value originally returned by the task function.<tr><td><a id="l2854"></a><a href="#l2854">2854</a><td> * @private<tr><td><a id="l2855"></a><a href="#l2855">2855</a><td> */<tr><td><a id="l2856"></a><a href="#l2856">2856</a><td> onTaskComplete_: function(value) {<tr><td><a id="l2857"></a><a href="#l2857">2857</a><td> if (this.pending_) {<tr><td><a id="l2858"></a><a href="#l2858">2858</a><td> this.pending_.task.fulfill(value);<tr><td><a id="l2859"></a><a href="#l2859">2859</a><td> }<tr><td><a id="l2860"></a><a href="#l2860">2860</a><td> },<tr><td><a id="l2861"></a><a href="#l2861">2861</a><td><tr><td><a id="l2862"></a><a href="#l2862">2862</a><td> /**<tr><td><a id="l2863"></a><a href="#l2863">2863</a><td> * @param {*} taskFnResult the value originally returned by the task function.<tr><td><a id="l2864"></a><a href="#l2864">2864</a><td> * @param {*} error the error that caused the task function to terminate.<tr><td><a id="l2865"></a><a href="#l2865">2865</a><td> * @private<tr><td><a id="l2866"></a><a href="#l2866">2866</a><td> */<tr><td><a id="l2867"></a><a href="#l2867">2867</a><td> onTaskFailure_: function(taskFnResult, error) {<tr><td><a id="l2868"></a><a href="#l2868">2868</a><td> if (promise.Thenable.isImplementation(taskFnResult)) {<tr><td><a id="l2869"></a><a href="#l2869">2869</a><td> taskFnResult.cancel(promise.CancellationError.wrap(error));<tr><td><a id="l2870"></a><a href="#l2870">2870</a><td> }<tr><td><a id="l2871"></a><a href="#l2871">2871</a><td> this.pending_.task.reject(error);<tr><td><a id="l2872"></a><a href="#l2872">2872</a><td> },<tr><td><a id="l2873"></a><a href="#l2873">2873</a><td><tr><td><a id="l2874"></a><a href="#l2874">2874</a><td> /**<tr><td><a id="l2875"></a><a href="#l2875">2875</a><td> * @return {(Task|undefined)} the next task scheduled within this queue,<tr><td><a id="l2876"></a><a href="#l2876">2876</a><td> * if any.<tr><td><a id="l2877"></a><a href="#l2877">2877</a><td> * @private<tr><td><a id="l2878"></a><a href="#l2878">2878</a><td> */<tr><td><a id="l2879"></a><a href="#l2879">2879</a><td> getNextTask_: function() {<tr><td><a id="l2880"></a><a href="#l2880">2880</a><td> var task = undefined;<tr><td><a id="l2881"></a><a href="#l2881">2881</a><td> while (true) {<tr><td><a id="l2882"></a><a href="#l2882">2882</a><td> if (this.interrupts_) {<tr><td><a id="l2883"></a><a href="#l2883">2883</a><td> task = this.interrupts_.shift();<tr><td><a id="l2884"></a><a href="#l2884">2884</a><td> }<tr><td><a id="l2885"></a><a href="#l2885">2885</a><td> if (!task &amp;&amp; this.tasks_) {<tr><td><a id="l2886"></a><a href="#l2886">2886</a><td> task = this.tasks_.shift();<tr><td><a id="l2887"></a><a href="#l2887">2887</a><td> }<tr><td><a id="l2888"></a><a href="#l2888">2888</a><td> if (task &amp;&amp; task.blocked) {<tr><td><a id="l2889"></a><a href="#l2889">2889</a><td> vlog(2, () =&gt; this + &#39; skipping blocked task &#39; + task, this);<tr><td><a id="l2890"></a><a href="#l2890">2890</a><td> task.queue = null;<tr><td><a id="l2891"></a><a href="#l2891">2891</a><td> task = null;<tr><td><a id="l2892"></a><a href="#l2892">2892</a><td> // TODO: recurse when tail-call optimization is available in node.<tr><td><a id="l2893"></a><a href="#l2893">2893</a><td> } else {<tr><td><a id="l2894"></a><a href="#l2894">2894</a><td> break;<tr><td><a id="l2895"></a><a href="#l2895">2895</a><td> }<tr><td><a id="l2896"></a><a href="#l2896">2896</a><td> }<tr><td><a id="l2897"></a><a href="#l2897">2897</a><td> return task;<tr><td><a id="l2898"></a><a href="#l2898">2898</a><td> }<tr><td><a id="l2899"></a><a href="#l2899">2899</a><td>});<tr><td><a id="l2900"></a><a href="#l2900">2900</a><td><tr><td><a id="l2901"></a><a href="#l2901">2901</a><td><tr><td><a id="l2902"></a><a href="#l2902">2902</a><td><tr><td><a id="l2903"></a><a href="#l2903">2903</a><td>/**<tr><td><a id="l2904"></a><a href="#l2904">2904</a><td> * The default flow to use if no others are active.<tr><td><a id="l2905"></a><a href="#l2905">2905</a><td> * @type {!promise.ControlFlow}<tr><td><a id="l2906"></a><a href="#l2906">2906</a><td> */<tr><td><a id="l2907"></a><a href="#l2907">2907</a><td>var defaultFlow = new promise.ControlFlow();<tr><td><a id="l2908"></a><a href="#l2908">2908</a><td><tr><td><a id="l2909"></a><a href="#l2909">2909</a><td><tr><td><a id="l2910"></a><a href="#l2910">2910</a><td>/**<tr><td><a id="l2911"></a><a href="#l2911">2911</a><td> * A stack of active control flows, with the top of the stack used to schedule<tr><td><a id="l2912"></a><a href="#l2912">2912</a><td> * commands. When there are multiple flows on the stack, the flow at index N<tr><td><a id="l2913"></a><a href="#l2913">2913</a><td> * represents a callback triggered within a task owned by the flow at index<tr><td><a id="l2914"></a><a href="#l2914">2914</a><td> * N-1.<tr><td><a id="l2915"></a><a href="#l2915">2915</a><td> * @type {!Array&lt;!promise.ControlFlow&gt;}<tr><td><a id="l2916"></a><a href="#l2916">2916</a><td> */<tr><td><a id="l2917"></a><a href="#l2917">2917</a><td>var activeFlows = [];<tr><td><a id="l2918"></a><a href="#l2918">2918</a><td><tr><td><a id="l2919"></a><a href="#l2919">2919</a><td><tr><td><a id="l2920"></a><a href="#l2920">2920</a><td>/**<tr><td><a id="l2921"></a><a href="#l2921">2921</a><td> * Changes the default flow to use when no others are active.<tr><td><a id="l2922"></a><a href="#l2922">2922</a><td> * @param {!promise.ControlFlow} flow The new default flow.<tr><td><a id="l2923"></a><a href="#l2923">2923</a><td> * @throws {Error} If the default flow is not currently active.<tr><td><a id="l2924"></a><a href="#l2924">2924</a><td> */<tr><td><a id="l2925"></a><a href="#l2925">2925</a><td>promise.setDefaultFlow = function(flow) {<tr><td><a id="l2926"></a><a href="#l2926">2926</a><td> if (activeFlows.length) {<tr><td><a id="l2927"></a><a href="#l2927">2927</a><td> throw Error(&#39;You may only change the default flow while it is active&#39;);<tr><td><a id="l2928"></a><a href="#l2928">2928</a><td> }<tr><td><a id="l2929"></a><a href="#l2929">2929</a><td> defaultFlow = flow;<tr><td><a id="l2930"></a><a href="#l2930">2930</a><td>};<tr><td><a id="l2931"></a><a href="#l2931">2931</a><td><tr><td><a id="l2932"></a><a href="#l2932">2932</a><td><tr><td><a id="l2933"></a><a href="#l2933">2933</a><td>/**<tr><td><a id="l2934"></a><a href="#l2934">2934</a><td> * @return {!promise.ControlFlow} The currently active control flow.<tr><td><a id="l2935"></a><a href="#l2935">2935</a><td> */<tr><td><a id="l2936"></a><a href="#l2936">2936</a><td>promise.controlFlow = function() {<tr><td><a id="l2937"></a><a href="#l2937">2937</a><td> return /** @type {!promise.ControlFlow} */ (<tr><td><a id="l2938"></a><a href="#l2938">2938</a><td> Arrays.peek(activeFlows) || defaultFlow);<tr><td><a id="l2939"></a><a href="#l2939">2939</a><td>};<tr><td><a id="l2940"></a><a href="#l2940">2940</a><td><tr><td><a id="l2941"></a><a href="#l2941">2941</a><td><tr><td><a id="l2942"></a><a href="#l2942">2942</a><td>/**<tr><td><a id="l2943"></a><a href="#l2943">2943</a><td> * Creates a new control flow. The provided callback will be invoked as the<tr><td><a id="l2944"></a><a href="#l2944">2944</a><td> * first task within the new flow, with the flow as its sole argument. Returns<tr><td><a id="l2945"></a><a href="#l2945">2945</a><td> * a promise that resolves to the callback result.<tr><td><a id="l2946"></a><a href="#l2946">2946</a><td> * @param {function(!promise.ControlFlow)} callback The entry point<tr><td><a id="l2947"></a><a href="#l2947">2947</a><td> * to the newly created flow.<tr><td><a id="l2948"></a><a href="#l2948">2948</a><td> * @return {!promise.Promise} A promise that resolves to the callback<tr><td><a id="l2949"></a><a href="#l2949">2949</a><td> * result.<tr><td><a id="l2950"></a><a href="#l2950">2950</a><td> */<tr><td><a id="l2951"></a><a href="#l2951">2951</a><td>promise.createFlow = function(callback) {<tr><td><a id="l2952"></a><a href="#l2952">2952</a><td> var flow = new promise.ControlFlow;<tr><td><a id="l2953"></a><a href="#l2953">2953</a><td> return flow.execute(function() {<tr><td><a id="l2954"></a><a href="#l2954">2954</a><td> return callback(flow);<tr><td><a id="l2955"></a><a href="#l2955">2955</a><td> });<tr><td><a id="l2956"></a><a href="#l2956">2956</a><td>};<tr><td><a id="l2957"></a><a href="#l2957">2957</a><td><tr><td><a id="l2958"></a><a href="#l2958">2958</a><td><tr><td><a id="l2959"></a><a href="#l2959">2959</a><td>/**<tr><td><a id="l2960"></a><a href="#l2960">2960</a><td> * Tests is a function is a generator.<tr><td><a id="l2961"></a><a href="#l2961">2961</a><td> * @param {!Function} fn The function to test.<tr><td><a id="l2962"></a><a href="#l2962">2962</a><td> * @return {boolean} Whether the function is a generator.<tr><td><a id="l2963"></a><a href="#l2963">2963</a><td> */<tr><td><a id="l2964"></a><a href="#l2964">2964</a><td>promise.isGenerator = function(fn) {<tr><td><a id="l2965"></a><a href="#l2965">2965</a><td> return fn.constructor.name === &#39;GeneratorFunction&#39;;<tr><td><a id="l2966"></a><a href="#l2966">2966</a><td>};<tr><td><a id="l2967"></a><a href="#l2967">2967</a><td><tr><td><a id="l2968"></a><a href="#l2968">2968</a><td><tr><td><a id="l2969"></a><a href="#l2969">2969</a><td>/**<tr><td><a id="l2970"></a><a href="#l2970">2970</a><td> * Consumes a {@code GeneratorFunction}. Each time the generator yields a<tr><td><a id="l2971"></a><a href="#l2971">2971</a><td> * promise, this function will wait for it to be fulfilled before feeding the<tr><td><a id="l2972"></a><a href="#l2972">2972</a><td> * fulfilled value back into {@code next}. Likewise, if a yielded promise is<tr><td><a id="l2973"></a><a href="#l2973">2973</a><td> * rejected, the rejection error will be passed to {@code throw}.<tr><td><a id="l2974"></a><a href="#l2974">2974</a><td> *<tr><td><a id="l2975"></a><a href="#l2975">2975</a><td> * __Example 1:__ the Fibonacci Sequence.<tr><td><a id="l2976"></a><a href="#l2976">2976</a><td> *<tr><td><a id="l2977"></a><a href="#l2977">2977</a><td> * promise.consume(function* fibonacci() {<tr><td><a id="l2978"></a><a href="#l2978">2978</a><td> * var n1 = 1, n2 = 1;<tr><td><a id="l2979"></a><a href="#l2979">2979</a><td> * for (var i = 0; i &lt; 4; ++i) {<tr><td><a id="l2980"></a><a href="#l2980">2980</a><td> * var tmp = yield n1 + n2;<tr><td><a id="l2981"></a><a href="#l2981">2981</a><td> * n1 = n2;<tr><td><a id="l2982"></a><a href="#l2982">2982</a><td> * n2 = tmp;<tr><td><a id="l2983"></a><a href="#l2983">2983</a><td> * }<tr><td><a id="l2984"></a><a href="#l2984">2984</a><td> * return n1 + n2;<tr><td><a id="l2985"></a><a href="#l2985">2985</a><td> * }).then(function(result) {<tr><td><a id="l2986"></a><a href="#l2986">2986</a><td> * console.log(result); // 13<tr><td><a id="l2987"></a><a href="#l2987">2987</a><td> * });<tr><td><a id="l2988"></a><a href="#l2988">2988</a><td> *<tr><td><a id="l2989"></a><a href="#l2989">2989</a><td> * __Example 2:__ a generator that throws.<tr><td><a id="l2990"></a><a href="#l2990">2990</a><td> *<tr><td><a id="l2991"></a><a href="#l2991">2991</a><td> * promise.consume(function* () {<tr><td><a id="l2992"></a><a href="#l2992">2992</a><td> * yield promise.delayed(250).then(function() {<tr><td><a id="l2993"></a><a href="#l2993">2993</a><td> * throw Error(&#39;boom&#39;);<tr><td><a id="l2994"></a><a href="#l2994">2994</a><td> * });<tr><td><a id="l2995"></a><a href="#l2995">2995</a><td> * }).thenCatch(function(e) {<tr><td><a id="l2996"></a><a href="#l2996">2996</a><td> * console.log(e.toString()); // Error: boom<tr><td><a id="l2997"></a><a href="#l2997">2997</a><td> * });<tr><td><a id="l2998"></a><a href="#l2998">2998</a><td> *<tr><td><a id="l2999"></a><a href="#l2999">2999</a><td> * @param {!Function} generatorFn The generator function to execute.<tr><td><a id="l3000"></a><a href="#l3000">3000</a><td> * @param {Object=} opt_self The object to use as &quot;this&quot; when invoking the<tr><td><a id="l3001"></a><a href="#l3001">3001</a><td> * initial generator.<tr><td><a id="l3002"></a><a href="#l3002">3002</a><td> * @param {...*} var_args Any arguments to pass to the initial generator.<tr><td><a id="l3003"></a><a href="#l3003">3003</a><td> * @return {!promise.Promise&lt;?&gt;} A promise that will resolve to the<tr><td><a id="l3004"></a><a href="#l3004">3004</a><td> * generator&#39;s final result.<tr><td><a id="l3005"></a><a href="#l3005">3005</a><td> * @throws {TypeError} If the given function is not a generator.<tr><td><a id="l3006"></a><a href="#l3006">3006</a><td> */<tr><td><a id="l3007"></a><a href="#l3007">3007</a><td>promise.consume = function(generatorFn, opt_self, var_args) {<tr><td><a id="l3008"></a><a href="#l3008">3008</a><td> if (!promise.isGenerator(generatorFn)) {<tr><td><a id="l3009"></a><a href="#l3009">3009</a><td> throw new TypeError(&#39;Input is not a GeneratorFunction: &#39; +<tr><td><a id="l3010"></a><a href="#l3010">3010</a><td> generatorFn.constructor.name);<tr><td><a id="l3011"></a><a href="#l3011">3011</a><td> }<tr><td><a id="l3012"></a><a href="#l3012">3012</a><td><tr><td><a id="l3013"></a><a href="#l3013">3013</a><td> var deferred = promise.defer();<tr><td><a id="l3014"></a><a href="#l3014">3014</a><td> var generator = generatorFn.apply(opt_self, Arrays.slice(arguments, 2));<tr><td><a id="l3015"></a><a href="#l3015">3015</a><td> callNext();<tr><td><a id="l3016"></a><a href="#l3016">3016</a><td> return deferred.promise;<tr><td><a id="l3017"></a><a href="#l3017">3017</a><td><tr><td><a id="l3018"></a><a href="#l3018">3018</a><td> /** @param {*=} opt_value . */<tr><td><a id="l3019"></a><a href="#l3019">3019</a><td> function callNext(opt_value) {<tr><td><a id="l3020"></a><a href="#l3020">3020</a><td> pump(generator.next, opt_value);<tr><td><a id="l3021"></a><a href="#l3021">3021</a><td> }<tr><td><a id="l3022"></a><a href="#l3022">3022</a><td><tr><td><a id="l3023"></a><a href="#l3023">3023</a><td> /** @param {*=} opt_error . */<tr><td><a id="l3024"></a><a href="#l3024">3024</a><td> function callThrow(opt_error) {<tr><td><a id="l3025"></a><a href="#l3025">3025</a><td> // Dictionary lookup required because Closure compiler&#39;s built-in<tr><td><a id="l3026"></a><a href="#l3026">3026</a><td> // externs does not include GeneratorFunction.prototype.throw.<tr><td><a id="l3027"></a><a href="#l3027">3027</a><td> pump(generator[&#39;throw&#39;], opt_error);<tr><td><a id="l3028"></a><a href="#l3028">3028</a><td> }<tr><td><a id="l3029"></a><a href="#l3029">3029</a><td><tr><td><a id="l3030"></a><a href="#l3030">3030</a><td> function pump(fn, opt_arg) {<tr><td><a id="l3031"></a><a href="#l3031">3031</a><td> if (!deferred.isPending()) {<tr><td><a id="l3032"></a><a href="#l3032">3032</a><td> return; // Defererd was cancelled; silently abort.<tr><td><a id="l3033"></a><a href="#l3033">3033</a><td> }<tr><td><a id="l3034"></a><a href="#l3034">3034</a><td><tr><td><a id="l3035"></a><a href="#l3035">3035</a><td> try {<tr><td><a id="l3036"></a><a href="#l3036">3036</a><td> var result = fn.call(generator, opt_arg);<tr><td><a id="l3037"></a><a href="#l3037">3037</a><td> } catch (ex) {<tr><td><a id="l3038"></a><a href="#l3038">3038</a><td> deferred.reject(ex);<tr><td><a id="l3039"></a><a href="#l3039">3039</a><td> return;<tr><td><a id="l3040"></a><a href="#l3040">3040</a><td> }<tr><td><a id="l3041"></a><a href="#l3041">3041</a><td><tr><td><a id="l3042"></a><a href="#l3042">3042</a><td> if (result.done) {<tr><td><a id="l3043"></a><a href="#l3043">3043</a><td> deferred.fulfill(result.value);<tr><td><a id="l3044"></a><a href="#l3044">3044</a><td> return;<tr><td><a id="l3045"></a><a href="#l3045">3045</a><td> }<tr><td><a id="l3046"></a><a href="#l3046">3046</a><td><tr><td><a id="l3047"></a><a href="#l3047">3047</a><td> promise.asap(result.value, callNext, callThrow);<tr><td><a id="l3048"></a><a href="#l3048">3048</a><td> }<tr><td><a id="l3049"></a><a href="#l3049">3049</a><td>};</table></div></article><nav><h3><a href="../../../index.html" tabindex="2">Overview</a></h3><div><input type="checkbox" id="nav-modules" checked/><label for="nav-modules"><h3><span class="selectable" tabindex="2">Modules</span></h3></label><div id="nav-modules-view"></div></div><div><input type="checkbox" id="nav-types" checked/><label for="nav-types"><h3><span class="selectable" tabindex="2">Types</span></h3></label><div id="nav-types-view"></div></div><h3><a href="../../../Changes.html" tabindex="2">Changes</a></h3></nav></main><footer><div><a href="https://github.com/jleyba/js-dossier">Generated by dossier</a></div></footer><script src="../../../types.js"></script><script src="../../../dossier.js"></script>