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.
- package/CHANGES.md +116 -0
- package/NOTICE +1 -1
- package/README.md +59 -9
- package/builder.js +375 -358
- package/chrome.js +549 -586
- package/edge.js +378 -0
- package/error.js +9 -6
- package/example/google_search.js +1 -1
- package/example/google_search_generator.js +2 -4
- package/example/logging.js +6 -2
- package/example/sample.js +21 -0
- package/executors.js +11 -27
- package/firefox/binary.js +149 -98
- package/firefox/extension.js +15 -19
- package/firefox/index.js +256 -163
- package/firefox/profile.js +223 -243
- package/http/index.js +487 -81
- package/http/util.js +40 -36
- package/ie.js +288 -309
- package/index.js +34 -125
- package/io/exec.js +58 -39
- package/io/index.js +72 -60
- package/lib/README +4 -0
- package/lib/actions.js +596 -0
- package/lib/by.js +277 -0
- package/lib/capabilities.js +450 -0
- package/lib/{webdriver/command.js → command.js} +91 -72
- package/lib/{webdriver/button.js → devmode.js} +13 -8
- package/lib/error.js +690 -0
- package/lib/events.js +212 -0
- package/lib/firefox/amd64/libnoblur64.so +0 -0
- package/lib/firefox/i386/libnoblur.so +0 -0
- package/lib/firefox/webdriver.json +5 -1
- package/lib/firefox/webdriver.xpi +0 -0
- package/lib/{webdriver/key.js → input.js} +84 -2
- package/lib/logging.js +670 -0
- package/lib/{webdriver/promise.js → promise.js} +817 -644
- package/lib/safari/client.js +266 -214
- package/lib/session.js +80 -0
- package/lib/{webdriver/serializable.js → symbols.js} +16 -19
- package/lib/test/build.js +4 -4
- package/lib/test/data/click_tests/html5_submit_buttons.html +2 -1
- package/lib/test/data/click_tests/overlapping_elements.html +15 -4
- package/lib/test/data/click_tests/partially_overlapping_elements.html +124 -0
- package/lib/test/data/click_tests/wrapped_overlapping_elements.html +13 -0
- package/lib/test/data/hidden_partially.html +45 -0
- package/lib/test/data/readOnlyPage.html +1 -1
- package/lib/test/data/selectPage.html +18 -2
- package/lib/test/fileserver.js +3 -4
- package/lib/test/index.js +7 -3
- package/lib/test/resources.js +1 -1
- package/lib/until.js +376 -0
- package/lib/webdriver.js +2440 -0
- package/net/index.js +4 -0
- package/net/portprober.js +16 -12
- package/opera.js +295 -314
- package/package.json +6 -5
- package/phantomjs.js +144 -147
- package/proxy.js +10 -6
- package/remote/index.js +289 -238
- package/safari.js +326 -311
- package/test/chrome/options_test.js +11 -9
- package/test/element_finding_test.js +51 -13
- package/test/execute_script_test.js +17 -3
- package/test/firefox/firefox_test.js +0 -32
- package/test/http/http_test.js +671 -61
- package/test/http/util_test.js +25 -23
- package/test/io_test.js +67 -1
- package/test/lib/by_test.js +139 -0
- package/test/lib/capabilities_test.js +111 -0
- package/test/lib/error_test.js +325 -0
- package/test/lib/events_test.js +177 -0
- package/test/lib/logging_test.js +272 -0
- package/test/{promise_aplus_test.js → lib/promise_aplus_test.js} +4 -13
- package/test/lib/promise_error_test.js +808 -0
- package/test/lib/promise_flow_test.js +2282 -0
- package/test/lib/promise_generator_test.js +308 -0
- package/test/lib/promise_test.js +996 -0
- package/test/lib/testutil.js +90 -0
- package/test/lib/until_test.js +400 -0
- package/test/lib/webdriver_test.js +2157 -0
- package/test/page_loading_test.js +7 -9
- package/test/remote_test.js +50 -3
- package/test/session_test.js +53 -0
- package/test/stale_element_test.js +2 -2
- package/test/testing/assert_test.js +374 -0
- package/test/testing/index_test.js +9 -11
- package/testing/assert.js +334 -17
- package/testing/index.js +12 -2
- package/_base.js +0 -200
- package/docs/Changes.html +0 -356
- package/docs/class_bot_Error.html +0 -15
- package/docs/class_webdriver_ActionSequence.html +0 -115
- package/docs/class_webdriver_Alert.html +0 -24
- package/docs/class_webdriver_AlertPromise.html +0 -92
- package/docs/class_webdriver_Capabilities.html +0 -60
- package/docs/class_webdriver_Command.html +0 -15
- package/docs/class_webdriver_EventEmitter.html +0 -35
- package/docs/class_webdriver_FileDetector.html +0 -21
- package/docs/class_webdriver_Locator.html +0 -12
- package/docs/class_webdriver_Serializable.html +0 -9
- package/docs/class_webdriver_Session.html +0 -13
- package/docs/class_webdriver_TouchSequence.html +0 -49
- package/docs/class_webdriver_UnhandledAlertError.html +0 -18
- package/docs/class_webdriver_WebDriver.html +0 -313
- package/docs/class_webdriver_WebDriver_Logs.html +0 -15
- package/docs/class_webdriver_WebDriver_Navigation.html +0 -16
- package/docs/class_webdriver_WebDriver_Options.html +0 -41
- package/docs/class_webdriver_WebDriver_TargetLocator.html +0 -38
- package/docs/class_webdriver_WebDriver_Timeouts.html +0 -29
- package/docs/class_webdriver_WebDriver_Window.html +0 -27
- package/docs/class_webdriver_WebElement.html +0 -223
- package/docs/class_webdriver_WebElementPromise.html +0 -274
- package/docs/class_webdriver_http_Executor.html +0 -22
- package/docs/class_webdriver_http_Request.html +0 -12
- package/docs/class_webdriver_http_Response.html +0 -13
- package/docs/class_webdriver_logging_Entry.html +0 -15
- package/docs/class_webdriver_logging_Level.html +0 -55
- package/docs/class_webdriver_logging_LogRecord.html +0 -45
- package/docs/class_webdriver_logging_Logger.html +0 -119
- package/docs/class_webdriver_logging_Preferences.html +0 -8
- package/docs/class_webdriver_promise_CancellationError.html +0 -17
- package/docs/class_webdriver_promise_ControlFlow.html +0 -153
- package/docs/class_webdriver_promise_Deferred.html +0 -84
- package/docs/class_webdriver_promise_MultipleUnhandledRejectionError.html +0 -14
- package/docs/class_webdriver_promise_Promise.html +0 -75
- package/docs/class_webdriver_stacktrace_Frame.html +0 -20
- package/docs/class_webdriver_stacktrace_Snapshot.html +0 -6
- package/docs/class_webdriver_testing_Assertion.html +0 -99
- package/docs/class_webdriver_testing_Assertion_DelegatingMatcher_.html +0 -13
- package/docs/class_webdriver_testing_ContainsMatcher.html +0 -11
- package/docs/class_webdriver_testing_NegatedAssertion.html +0 -97
- package/docs/class_webdriver_until_Condition.html +0 -7
- package/docs/dossier.css +0 -1
- package/docs/dossier.js +0 -86
- package/docs/enum_bot_ErrorCode.html +0 -3
- package/docs/enum_bot_Error_State.html +0 -2
- package/docs/enum_webdriver_Browser.html +0 -2
- package/docs/enum_webdriver_Button.html +0 -2
- package/docs/enum_webdriver_Capability.html +0 -33
- package/docs/enum_webdriver_CommandName.html +0 -3
- package/docs/enum_webdriver_Key.html +0 -12
- package/docs/enum_webdriver_logging_Type.html +0 -6
- package/docs/enum_webdriver_promise_ControlFlow_EventType.html +0 -9
- package/docs/index.html +0 -125
- package/docs/interface_webdriver_CommandExecutor.html +0 -9
- package/docs/interface_webdriver_http_Client.html +0 -10
- package/docs/interface_webdriver_promise_Thenable.html +0 -77
- package/docs/module_selenium-webdriver.html +0 -23
- package/docs/module_selenium-webdriver__base.html +0 -23
- package/docs/module_selenium-webdriver__base_class_Context.html +0 -5
- package/docs/module_selenium-webdriver_builder.html +0 -2
- package/docs/module_selenium-webdriver_builder_class_Builder.html +0 -138
- package/docs/module_selenium-webdriver_chrome.html +0 -90
- package/docs/module_selenium-webdriver_chrome_class_Driver.html +0 -280
- package/docs/module_selenium-webdriver_chrome_class_Options.html +0 -127
- package/docs/module_selenium-webdriver_chrome_class_ServiceBuilder.html +0 -46
- package/docs/module_selenium-webdriver_class_ActionSequence.html +0 -115
- package/docs/module_selenium-webdriver_class_Builder.html +0 -138
- package/docs/module_selenium-webdriver_class_Capabilities.html +0 -60
- package/docs/module_selenium-webdriver_class_Command.html +0 -15
- package/docs/module_selenium-webdriver_class_EventEmitter.html +0 -35
- package/docs/module_selenium-webdriver_class_FileDetector.html +0 -21
- package/docs/module_selenium-webdriver_class_Serializable.html +0 -9
- package/docs/module_selenium-webdriver_class_Session.html +0 -13
- package/docs/module_selenium-webdriver_class_WebDriver.html +0 -313
- package/docs/module_selenium-webdriver_class_WebElement.html +0 -223
- package/docs/module_selenium-webdriver_class_WebElementPromise.html +0 -274
- package/docs/module_selenium-webdriver_enum_Browser.html +0 -2
- package/docs/module_selenium-webdriver_enum_Button.html +0 -2
- package/docs/module_selenium-webdriver_enum_Capability.html +0 -33
- package/docs/module_selenium-webdriver_enum_CommandName.html +0 -3
- package/docs/module_selenium-webdriver_enum_Key.html +0 -12
- package/docs/module_selenium-webdriver_error.html +0 -4
- package/docs/module_selenium-webdriver_error_class_Error.html +0 -15
- package/docs/module_selenium-webdriver_error_enum_ErrorCode.html +0 -3
- package/docs/module_selenium-webdriver_executors.html +0 -10
- package/docs/module_selenium-webdriver_executors_class_DeferredExecutor.html +0 -12
- package/docs/module_selenium-webdriver_firefox.html +0 -68
- package/docs/module_selenium-webdriver_firefox_binary.html +0 -5
- package/docs/module_selenium-webdriver_firefox_binary_class_Binary.html +0 -20
- package/docs/module_selenium-webdriver_firefox_class_Binary.html +0 -20
- package/docs/module_selenium-webdriver_firefox_class_Driver.html +0 -276
- package/docs/module_selenium-webdriver_firefox_class_Options.html +0 -19
- package/docs/module_selenium-webdriver_firefox_class_Profile.html +0 -50
- package/docs/module_selenium-webdriver_firefox_extension.html +0 -8
- package/docs/module_selenium-webdriver_firefox_profile.html +0 -13
- package/docs/module_selenium-webdriver_firefox_profile_class_Profile.html +0 -50
- package/docs/module_selenium-webdriver_http.html +0 -9
- package/docs/module_selenium-webdriver_http_class_Executor.html +0 -22
- package/docs/module_selenium-webdriver_http_class_HttpClient.html +0 -16
- package/docs/module_selenium-webdriver_http_class_Request.html +0 -12
- package/docs/module_selenium-webdriver_http_class_Response.html +0 -13
- package/docs/module_selenium-webdriver_http_util.html +0 -17
- package/docs/module_selenium-webdriver_ie.html +0 -11
- package/docs/module_selenium-webdriver_ie_class_Driver.html +0 -274
- package/docs/module_selenium-webdriver_ie_class_Options.html +0 -89
- package/docs/module_selenium-webdriver_ie_enum_Level.html +0 -1
- package/docs/module_selenium-webdriver_io.html +0 -37
- package/docs/module_selenium-webdriver_io_exec.html +0 -6
- package/docs/module_selenium-webdriver_namespace_By.html +0 -56
- package/docs/module_selenium-webdriver_namespace_error.html +0 -4
- package/docs/module_selenium-webdriver_namespace_logging.html +0 -18
- package/docs/module_selenium-webdriver_namespace_promise.html +0 -163
- package/docs/module_selenium-webdriver_namespace_stacktrace.html +0 -17
- package/docs/module_selenium-webdriver_namespace_until.html +0 -82
- package/docs/module_selenium-webdriver_net.html +0 -7
- package/docs/module_selenium-webdriver_net_portprober.html +0 -12
- package/docs/module_selenium-webdriver_opera.html +0 -62
- package/docs/module_selenium-webdriver_opera_class_Driver.html +0 -276
- package/docs/module_selenium-webdriver_opera_class_Options.html +0 -44
- package/docs/module_selenium-webdriver_opera_class_ServiceBuilder.html +0 -35
- package/docs/module_selenium-webdriver_phantomjs.html +0 -2
- package/docs/module_selenium-webdriver_phantomjs_class_Driver.html +0 -299
- package/docs/module_selenium-webdriver_proxy.html +0 -28
- package/docs/module_selenium-webdriver_remote.html +0 -8
- package/docs/module_selenium-webdriver_remote_class_DriverService.html +0 -32
- package/docs/module_selenium-webdriver_remote_class_FileDetector.html +0 -22
- package/docs/module_selenium-webdriver_remote_class_SeleniumServer.html +0 -41
- package/docs/module_selenium-webdriver_safari.html +0 -9
- package/docs/module_selenium-webdriver_safari_class_Driver.html +0 -279
- package/docs/module_selenium-webdriver_safari_class_Options.html +0 -23
- package/docs/module_selenium-webdriver_testing.html +0 -74
- package/docs/module_selenium-webdriver_testing_assert.html +0 -9
- package/docs/namespace_bot.html +0 -4
- package/docs/namespace_bot_json.html +0 -20
- package/docs/namespace_bot_response.html +0 -18
- package/docs/namespace_bot_userAgent.html +0 -33
- package/docs/namespace_webdriver.html +0 -30
- package/docs/namespace_webdriver_By.html +0 -56
- package/docs/namespace_webdriver_http.html +0 -6
- package/docs/namespace_webdriver_logging.html +0 -70
- package/docs/namespace_webdriver_promise.html +0 -688
- package/docs/namespace_webdriver_stacktrace.html +0 -17
- package/docs/namespace_webdriver_testing.html +0 -7
- package/docs/namespace_webdriver_testing_assert.html +0 -9
- package/docs/namespace_webdriver_testing_asserts.html +0 -18
- package/docs/namespace_webdriver_until.html +0 -82
- package/docs/source/_base.js.src.html +0 -1
- package/docs/source/builder.js.src.html +0 -1
- package/docs/source/chrome.js.src.html +0 -1
- package/docs/source/error.js.src.html +0 -1
- package/docs/source/executors.js.src.html +0 -1
- package/docs/source/firefox/binary.js.src.html +0 -1
- package/docs/source/firefox/extension.js.src.html +0 -1
- package/docs/source/firefox/index.js.src.html +0 -1
- package/docs/source/firefox/profile.js.src.html +0 -1
- package/docs/source/http/index.js.src.html +0 -1
- package/docs/source/http/util.js.src.html +0 -1
- package/docs/source/ie.js.src.html +0 -1
- package/docs/source/index.js.src.html +0 -1
- package/docs/source/io/exec.js.src.html +0 -1
- package/docs/source/io/index.js.src.html +0 -1
- package/docs/source/lib/atoms/error.js.src.html +0 -1
- package/docs/source/lib/atoms/json.js.src.html +0 -1
- package/docs/source/lib/atoms/response.js.src.html +0 -1
- package/docs/source/lib/atoms/userAgent.js.src.html +0 -1
- package/docs/source/lib/goog/array/array.js.src.html +0 -1
- package/docs/source/lib/goog/asserts/asserts.js.src.html +0 -1
- package/docs/source/lib/goog/async/freelist.js.src.html +0 -1
- package/docs/source/lib/goog/async/nexttick.js.src.html +0 -1
- package/docs/source/lib/goog/async/run.js.src.html +0 -1
- package/docs/source/lib/goog/async/workqueue.js.src.html +0 -1
- package/docs/source/lib/goog/base.js.src.html +0 -1
- package/docs/source/lib/goog/debug/debug.js.src.html +0 -1
- package/docs/source/lib/goog/debug/entrypointregistry.js.src.html +0 -1
- package/docs/source/lib/goog/debug/error.js.src.html +0 -1
- package/docs/source/lib/goog/debug/logbuffer.js.src.html +0 -1
- package/docs/source/lib/goog/debug/logger.js.src.html +0 -1
- package/docs/source/lib/goog/debug/logrecord.js.src.html +0 -1
- package/docs/source/lib/goog/deps.js.src.html +0 -1
- package/docs/source/lib/goog/disposable/disposable.js.src.html +0 -1
- package/docs/source/lib/goog/disposable/idisposable.js.src.html +0 -1
- package/docs/source/lib/goog/dom/browserfeature.js.src.html +0 -1
- package/docs/source/lib/goog/dom/dom.js.src.html +0 -1
- package/docs/source/lib/goog/dom/nodetype.js.src.html +0 -1
- package/docs/source/lib/goog/dom/safe.js.src.html +0 -1
- package/docs/source/lib/goog/dom/tagname.js.src.html +0 -1
- package/docs/source/lib/goog/dom/tags.js.src.html +0 -1
- package/docs/source/lib/goog/dom/vendor.js.src.html +0 -1
- package/docs/source/lib/goog/events/browserevent.js.src.html +0 -1
- package/docs/source/lib/goog/events/browserfeature.js.src.html +0 -1
- package/docs/source/lib/goog/events/event.js.src.html +0 -1
- package/docs/source/lib/goog/events/eventid.js.src.html +0 -1
- package/docs/source/lib/goog/events/events.js.src.html +0 -1
- package/docs/source/lib/goog/events/eventtarget.js.src.html +0 -1
- package/docs/source/lib/goog/events/eventtype.js.src.html +0 -1
- package/docs/source/lib/goog/events/keycodes.js.src.html +0 -1
- package/docs/source/lib/goog/events/listenable.js.src.html +0 -1
- package/docs/source/lib/goog/events/listener.js.src.html +0 -1
- package/docs/source/lib/goog/events/listenermap.js.src.html +0 -1
- package/docs/source/lib/goog/fs/url.js.src.html +0 -1
- package/docs/source/lib/goog/functions/functions.js.src.html +0 -1
- package/docs/source/lib/goog/html/safehtml.js.src.html +0 -1
- package/docs/source/lib/goog/html/safescript.js.src.html +0 -1
- package/docs/source/lib/goog/html/safestyle.js.src.html +0 -1
- package/docs/source/lib/goog/html/safestylesheet.js.src.html +0 -1
- package/docs/source/lib/goog/html/safeurl.js.src.html +0 -1
- package/docs/source/lib/goog/html/trustedresourceurl.js.src.html +0 -1
- package/docs/source/lib/goog/html/uncheckedconversions.js.src.html +0 -1
- package/docs/source/lib/goog/i18n/bidi.js.src.html +0 -1
- package/docs/source/lib/goog/iter/iter.js.src.html +0 -1
- package/docs/source/lib/goog/json/json.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/assertthat.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/logicmatcher.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/matcher.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/numbermatcher.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/objectmatcher.js.src.html +0 -1
- package/docs/source/lib/goog/labs/testing/stringmatcher.js.src.html +0 -1
- package/docs/source/lib/goog/labs/useragent/browser.js.src.html +0 -1
- package/docs/source/lib/goog/labs/useragent/engine.js.src.html +0 -1
- package/docs/source/lib/goog/labs/useragent/platform.js.src.html +0 -1
- package/docs/source/lib/goog/labs/useragent/util.js.src.html +0 -1
- package/docs/source/lib/goog/log/log.js.src.html +0 -1
- package/docs/source/lib/goog/math/box.js.src.html +0 -1
- package/docs/source/lib/goog/math/coordinate.js.src.html +0 -1
- package/docs/source/lib/goog/math/math.js.src.html +0 -1
- package/docs/source/lib/goog/math/rect.js.src.html +0 -1
- package/docs/source/lib/goog/math/size.js.src.html +0 -1
- package/docs/source/lib/goog/net/wrapperxmlhttpfactory.js.src.html +0 -1
- package/docs/source/lib/goog/net/xhrlike.js.src.html +0 -1
- package/docs/source/lib/goog/net/xmlhttp.js.src.html +0 -1
- package/docs/source/lib/goog/net/xmlhttpfactory.js.src.html +0 -1
- package/docs/source/lib/goog/object/object.js.src.html +0 -1
- package/docs/source/lib/goog/promise/promise.js.src.html +0 -1
- package/docs/source/lib/goog/promise/resolver.js.src.html +0 -1
- package/docs/source/lib/goog/promise/thenable.js.src.html +0 -1
- package/docs/source/lib/goog/reflect/reflect.js.src.html +0 -1
- package/docs/source/lib/goog/string/const.js.src.html +0 -1
- package/docs/source/lib/goog/string/string.js.src.html +0 -1
- package/docs/source/lib/goog/string/typedstring.js.src.html +0 -1
- package/docs/source/lib/goog/structs/collection.js.src.html +0 -1
- package/docs/source/lib/goog/structs/map.js.src.html +0 -1
- package/docs/source/lib/goog/structs/set.js.src.html +0 -1
- package/docs/source/lib/goog/structs/structs.js.src.html +0 -1
- package/docs/source/lib/goog/style/style.js.src.html +0 -1
- package/docs/source/lib/goog/testing/asserts.js.src.html +0 -1
- package/docs/source/lib/goog/testing/events/events.js.src.html +0 -1
- package/docs/source/lib/goog/testing/functionmock.js.src.html +0 -1
- package/docs/source/lib/goog/testing/jsunit.js.src.html +0 -1
- package/docs/source/lib/goog/testing/loosemock.js.src.html +0 -1
- package/docs/source/lib/goog/testing/mock.js.src.html +0 -1
- package/docs/source/lib/goog/testing/mockclock.js.src.html +0 -1
- package/docs/source/lib/goog/testing/mockcontrol.js.src.html +0 -1
- package/docs/source/lib/goog/testing/mockinterface.js.src.html +0 -1
- package/docs/source/lib/goog/testing/mockmatchers.js.src.html +0 -1
- package/docs/source/lib/goog/testing/objectpropertystring.js.src.html +0 -1
- package/docs/source/lib/goog/testing/propertyreplacer.js.src.html +0 -1
- package/docs/source/lib/goog/testing/recordfunction.js.src.html +0 -1
- package/docs/source/lib/goog/testing/stacktrace.js.src.html +0 -1
- package/docs/source/lib/goog/testing/strictmock.js.src.html +0 -1
- package/docs/source/lib/goog/testing/testcase.js.src.html +0 -1
- package/docs/source/lib/goog/testing/testrunner.js.src.html +0 -1
- package/docs/source/lib/goog/uri/uri.js.src.html +0 -1
- package/docs/source/lib/goog/uri/utils.js.src.html +0 -1
- package/docs/source/lib/goog/useragent/product.js.src.html +0 -1
- package/docs/source/lib/goog/useragent/product_isversion.js.src.html +0 -1
- package/docs/source/lib/goog/useragent/useragent.js.src.html +0 -1
- package/docs/source/lib/webdriver/actionsequence.js.src.html +0 -1
- package/docs/source/lib/webdriver/button.js.src.html +0 -1
- package/docs/source/lib/webdriver/capabilities.js.src.html +0 -1
- package/docs/source/lib/webdriver/command.js.src.html +0 -1
- package/docs/source/lib/webdriver/events.js.src.html +0 -1
- package/docs/source/lib/webdriver/http/http.js.src.html +0 -1
- package/docs/source/lib/webdriver/key.js.src.html +0 -1
- package/docs/source/lib/webdriver/locators.js.src.html +0 -1
- package/docs/source/lib/webdriver/logging.js.src.html +0 -1
- package/docs/source/lib/webdriver/promise.js.src.html +0 -1
- package/docs/source/lib/webdriver/serializable.js.src.html +0 -1
- package/docs/source/lib/webdriver/session.js.src.html +0 -1
- package/docs/source/lib/webdriver/stacktrace.js.src.html +0 -1
- package/docs/source/lib/webdriver/testing/asserts.js.src.html +0 -1
- package/docs/source/lib/webdriver/touchsequence.js.src.html +0 -1
- package/docs/source/lib/webdriver/until.js.src.html +0 -1
- package/docs/source/lib/webdriver/webdriver.js.src.html +0 -1
- package/docs/source/net/index.js.src.html +0 -1
- package/docs/source/net/portprober.js.src.html +0 -1
- package/docs/source/opera.js.src.html +0 -1
- package/docs/source/phantomjs.js.src.html +0 -1
- package/docs/source/proxy.js.src.html +0 -1
- package/docs/source/remote/index.js.src.html +0 -1
- package/docs/source/safari.js.src.html +0 -1
- package/docs/source/testing/assert.js.src.html +0 -1
- package/docs/source/testing/index.js.src.html +0 -1
- package/docs/types.js +0 -1
- package/lib/atoms/error.js +0 -202
- package/lib/atoms/json.js +0 -80
- package/lib/atoms/response.js +0 -110
- package/lib/atoms/userAgent.js +0 -257
- package/lib/goog/LICENSE +0 -176
- package/lib/goog/array/array.js +0 -1654
- package/lib/goog/asserts/asserts.js +0 -365
- package/lib/goog/async/freelist.js +0 -88
- package/lib/goog/async/nexttick.js +0 -241
- package/lib/goog/async/run.js +0 -133
- package/lib/goog/async/workqueue.js +0 -139
- package/lib/goog/base.js +0 -2548
- package/lib/goog/debug/debug.js +0 -653
- package/lib/goog/debug/entrypointregistry.js +0 -158
- package/lib/goog/debug/error.js +0 -63
- package/lib/goog/debug/logbuffer.js +0 -148
- package/lib/goog/debug/logger.js +0 -873
- package/lib/goog/debug/logrecord.js +0 -242
- package/lib/goog/deps.js +0 -151
- package/lib/goog/disposable/disposable.js +0 -307
- package/lib/goog/disposable/idisposable.js +0 -45
- package/lib/goog/dom/browserfeature.js +0 -72
- package/lib/goog/dom/dom.js +0 -2991
- package/lib/goog/dom/nodetype.js +0 -48
- package/lib/goog/dom/safe.js +0 -347
- package/lib/goog/dom/tagname.js +0 -160
- package/lib/goog/dom/tags.js +0 -41
- package/lib/goog/dom/vendor.js +0 -96
- package/lib/goog/events/browserevent.js +0 -400
- package/lib/goog/events/browserfeature.js +0 -85
- package/lib/goog/events/event.js +0 -143
- package/lib/goog/events/eventid.js +0 -47
- package/lib/goog/events/events.js +0 -984
- package/lib/goog/events/eventtarget.js +0 -394
- package/lib/goog/events/eventtype.js +0 -237
- package/lib/goog/events/keycodes.js +0 -427
- package/lib/goog/events/listenable.js +0 -335
- package/lib/goog/events/listener.js +0 -131
- package/lib/goog/events/listenermap.js +0 -308
- package/lib/goog/fs/url.js +0 -109
- package/lib/goog/functions/functions.js +0 -442
- package/lib/goog/html/safehtml.js +0 -757
- package/lib/goog/html/safescript.js +0 -234
- package/lib/goog/html/safestyle.js +0 -442
- package/lib/goog/html/safestylesheet.js +0 -276
- package/lib/goog/html/safeurl.js +0 -398
- package/lib/goog/html/trustedresourceurl.js +0 -224
- package/lib/goog/html/uncheckedconversions.js +0 -232
- package/lib/goog/i18n/bidi.js +0 -908
- package/lib/goog/iter/iter.js +0 -1302
- package/lib/goog/json/json.js +0 -363
- package/lib/goog/labs/testing/assertthat.js +0 -58
- package/lib/goog/labs/testing/logicmatcher.js +0 -212
- package/lib/goog/labs/testing/matcher.js +0 -80
- package/lib/goog/labs/testing/numbermatcher.js +0 -346
- package/lib/goog/labs/testing/objectmatcher.js +0 -317
- package/lib/goog/labs/testing/stringmatcher.js +0 -415
- package/lib/goog/labs/useragent/browser.js +0 -341
- package/lib/goog/labs/useragent/engine.js +0 -160
- package/lib/goog/labs/useragent/platform.js +0 -160
- package/lib/goog/labs/useragent/util.js +0 -148
- package/lib/goog/log/log.js +0 -197
- package/lib/goog/math/box.js +0 -398
- package/lib/goog/math/coordinate.js +0 -268
- package/lib/goog/math/math.js +0 -451
- package/lib/goog/math/rect.js +0 -476
- package/lib/goog/math/size.js +0 -227
- package/lib/goog/net/wrapperxmlhttpfactory.js +0 -71
- package/lib/goog/net/xhrlike.js +0 -124
- package/lib/goog/net/xmlhttp.js +0 -246
- package/lib/goog/net/xmlhttpfactory.js +0 -67
- package/lib/goog/object/object.js +0 -686
- package/lib/goog/promise/promise.js +0 -1350
- package/lib/goog/promise/resolver.js +0 -48
- package/lib/goog/promise/thenable.js +0 -126
- package/lib/goog/reflect/reflect.js +0 -77
- package/lib/goog/string/const.js +0 -182
- package/lib/goog/string/string.js +0 -1599
- package/lib/goog/string/typedstring.js +0 -48
- package/lib/goog/structs/collection.js +0 -56
- package/lib/goog/structs/map.js +0 -457
- package/lib/goog/structs/set.js +0 -279
- package/lib/goog/structs/structs.js +0 -354
- package/lib/goog/style/style.js +0 -2037
- package/lib/goog/testing/asserts.js +0 -1278
- package/lib/goog/testing/events/events.js +0 -767
- package/lib/goog/testing/functionmock.js +0 -175
- package/lib/goog/testing/jsunit.js +0 -162
- package/lib/goog/testing/loosemock.js +0 -242
- package/lib/goog/testing/mock.js +0 -645
- package/lib/goog/testing/mockclock.js +0 -606
- package/lib/goog/testing/mockcontrol.js +0 -220
- package/lib/goog/testing/mockinterface.js +0 -45
- package/lib/goog/testing/mockmatchers.js +0 -400
- package/lib/goog/testing/objectpropertystring.js +0 -68
- package/lib/goog/testing/propertyreplacer.js +0 -262
- package/lib/goog/testing/recordfunction.js +0 -215
- package/lib/goog/testing/stacktrace.js +0 -594
- package/lib/goog/testing/strictmock.js +0 -130
- package/lib/goog/testing/testcase.js +0 -1629
- package/lib/goog/testing/testrunner.js +0 -440
- package/lib/goog/uri/uri.js +0 -1524
- package/lib/goog/uri/utils.js +0 -1064
- package/lib/goog/useragent/product.js +0 -183
- package/lib/goog/useragent/product_isversion.js +0 -144
- package/lib/goog/useragent/useragent.js +0 -572
- package/lib/webdriver/actionsequence.js +0 -356
- package/lib/webdriver/builder.js +0 -207
- package/lib/webdriver/capabilities.js +0 -412
- package/lib/webdriver/events.js +0 -179
- package/lib/webdriver/firefoxdomexecutor.js +0 -175
- package/lib/webdriver/http/corsclient.js +0 -133
- package/lib/webdriver/http/http.js +0 -525
- package/lib/webdriver/http/xhrclient.js +0 -67
- package/lib/webdriver/locators.js +0 -257
- package/lib/webdriver/logging.js +0 -347
- package/lib/webdriver/session.js +0 -74
- package/lib/webdriver/stacktrace.js +0 -619
- package/lib/webdriver/test/builder_test.js +0 -53
- package/lib/webdriver/test/capabilities_test.js +0 -72
- package/lib/webdriver/test/events_test.js +0 -203
- package/lib/webdriver/test/http/corsclient_test.js +0 -151
- package/lib/webdriver/test/http/http_test.js +0 -428
- package/lib/webdriver/test/http/xhrclient_test.js +0 -196
- package/lib/webdriver/test/locators_test.js +0 -59
- package/lib/webdriver/test/logging_test.js +0 -85
- package/lib/webdriver/test/promise_error_test.js +0 -892
- package/lib/webdriver/test/promise_flow_test.js +0 -2365
- package/lib/webdriver/test/promise_generator_test.js +0 -323
- package/lib/webdriver/test/promise_test.js +0 -2012
- package/lib/webdriver/test/stacktrace_test.js +0 -480
- package/lib/webdriver/test/test_bootstrap.js +0 -67
- package/lib/webdriver/test/testing/asserts_test.js +0 -117
- package/lib/webdriver/test/testing/client_test.js +0 -88
- package/lib/webdriver/test/testing/testcase_test.js +0 -229
- package/lib/webdriver/test/testutil.js +0 -209
- package/lib/webdriver/test/testutil_test.js +0 -104
- package/lib/webdriver/test/until_test.js +0 -411
- package/lib/webdriver/test/webdriver_generator_test.js +0 -92
- package/lib/webdriver/test/webdriver_test.js +0 -2369
- package/lib/webdriver/testing/asserts.js +0 -487
- package/lib/webdriver/testing/client.js +0 -179
- package/lib/webdriver/testing/jsunit.js +0 -363
- package/lib/webdriver/testing/testcase.js +0 -168
- package/lib/webdriver/testing/window.js +0 -244
- package/lib/webdriver/touchsequence.js +0 -248
- package/lib/webdriver/until.js +0 -412
- package/lib/webdriver/webdriver.js +0 -2511
- package/test/_base_test.js +0 -129
|
@@ -15,44 +15,15 @@
|
|
|
15
15
|
// specific language governing permissions and limitations
|
|
16
16
|
// under the License.
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @license Portions of this code are from the Dojo toolkit, received under the
|
|
20
|
-
* BSD License:
|
|
21
|
-
* Redistribution and use in source and binary forms, with or without
|
|
22
|
-
* modification, are permitted provided that the following conditions are met:
|
|
23
|
-
*
|
|
24
|
-
* * Redistributions of source code must retain the above copyright notice,
|
|
25
|
-
* this list of conditions and the following disclaimer.
|
|
26
|
-
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
27
|
-
* this list of conditions and the following disclaimer in the documentation
|
|
28
|
-
* and/or other materials provided with the distribution.
|
|
29
|
-
* * Neither the name of the Dojo Foundation nor the names of its contributors
|
|
30
|
-
* may be used to endorse or promote products derived from this software
|
|
31
|
-
* without specific prior written permission.
|
|
32
|
-
*
|
|
33
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
34
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
35
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
36
|
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
37
|
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
38
|
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
39
|
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
40
|
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
41
|
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
42
|
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
43
|
-
* POSSIBILITY OF SUCH DAMAGE.
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
18
|
/**
|
|
47
19
|
* @fileoverview
|
|
48
|
-
* The promise module is centered around the
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* {@linkplain webdriver.WebDriver WebDriver} API is built on top of the
|
|
20
|
+
* The promise module is centered around the {@linkplain ControlFlow}, a class
|
|
21
|
+
* that coordinates the execution of asynchronous tasks. The ControlFlow allows
|
|
22
|
+
* users to focus on the imperative commands for their script without worrying
|
|
23
|
+
* about chaining together every single asynchronous action, which can be
|
|
24
|
+
* tedious and verbose. APIs may be layered on top of the control flow to read
|
|
25
|
+
* as if they were synchronous. For instance, the core
|
|
26
|
+
* {@linkplain ./webdriver.WebDriver WebDriver} API is built on top of the
|
|
56
27
|
* control flow, allowing users to write
|
|
57
28
|
*
|
|
58
29
|
* driver.get('http://www.google.com/ncr');
|
|
@@ -79,10 +50,9 @@
|
|
|
79
50
|
*
|
|
80
51
|
* The control flow is based on the concept of tasks and task queues. Tasks are
|
|
81
52
|
* functions that define the basic unit of work for the control flow to execute.
|
|
82
|
-
* Each task is scheduled via
|
|
83
|
-
* {@link
|
|
84
|
-
*
|
|
85
|
-
* with the task's result.
|
|
53
|
+
* Each task is scheduled via {@link ControlFlow#execute()}, which will return
|
|
54
|
+
* a {@link ManagedPromise ManagedPromise} that will be resolved with the task's
|
|
55
|
+
* result.
|
|
86
56
|
*
|
|
87
57
|
* A task queue contains all of the tasks scheduled within a single turn of the
|
|
88
58
|
* [JavaScript event loop][JSEL]. The control flow will create a new task queue
|
|
@@ -98,12 +68,12 @@
|
|
|
98
68
|
* Whenever the control flow creates a new task queue, it will automatically
|
|
99
69
|
* begin executing tasks in the next available turn of the event loop. This
|
|
100
70
|
* execution is scheduled using a "micro-task" timer, such as a (native)
|
|
101
|
-
* `
|
|
71
|
+
* `ManagedPromise.then()` callback.
|
|
102
72
|
*
|
|
103
73
|
* setTimeout(() => console.log('a'));
|
|
104
|
-
*
|
|
74
|
+
* ManagedPromise.resolve().then(() => console.log('b')); // A native promise.
|
|
105
75
|
* flow.execute(() => console.log('c'));
|
|
106
|
-
*
|
|
76
|
+
* ManagedPromise.resolve().then(() => console.log('d'));
|
|
107
77
|
* setTimeout(() => console.log('fin'));
|
|
108
78
|
* // b
|
|
109
79
|
* // c
|
|
@@ -127,14 +97,13 @@
|
|
|
127
97
|
* There are several important events that may occur while executing a task
|
|
128
98
|
* function:
|
|
129
99
|
*
|
|
130
|
-
* 1. A new task queue is created by a call to
|
|
131
|
-
*
|
|
132
|
-
* tasks scheduled within this task queue are considered subtasks of the
|
|
100
|
+
* 1. A new task queue is created by a call to {@link ControlFlow#execute()}.
|
|
101
|
+
* Any tasks scheduled within this task queue are considered subtasks of the
|
|
133
102
|
* current task.
|
|
134
103
|
* 2. The task function throws an error. Any scheduled tasks are immediately
|
|
135
104
|
* discarded and the task's promised result (previously returned by
|
|
136
|
-
* {@link
|
|
137
|
-
*
|
|
105
|
+
* {@link ControlFlow#execute()}) is immediately rejected with the thrown
|
|
106
|
+
* error.
|
|
138
107
|
* 3. The task function returns sucessfully.
|
|
139
108
|
*
|
|
140
109
|
* If a task function created a new task queue, the control flow will wait for
|
|
@@ -153,13 +122,12 @@
|
|
|
153
122
|
* // b
|
|
154
123
|
* // c
|
|
155
124
|
*
|
|
156
|
-
* ##
|
|
125
|
+
* ## ManagedPromise Integration
|
|
157
126
|
*
|
|
158
|
-
* In addition to the {@link
|
|
159
|
-
*
|
|
160
|
-
* {@linkplain webdriver.promise.Promise implementation} that is deeply
|
|
127
|
+
* In addition to the {@link ControlFlow} class, the promise module also exports
|
|
128
|
+
* a [ManagedPromise/A+] {@linkplain ManagedPromise implementation} that is deeply
|
|
161
129
|
* integrated with the ControlFlow. First and foremost, each promise
|
|
162
|
-
* {@linkplain
|
|
130
|
+
* {@linkplain ManagedPromise#then() callback} is scheduled with the
|
|
163
131
|
* control flow as a task. As a result, each callback is invoked in its own turn
|
|
164
132
|
* of the JavaScript event loop with its own task queue. If any tasks are
|
|
165
133
|
* scheduled within a callback, the callback's promised result will not be
|
|
@@ -173,7 +141,7 @@
|
|
|
173
141
|
* // b
|
|
174
142
|
* // a
|
|
175
143
|
*
|
|
176
|
-
* ### Scheduling
|
|
144
|
+
* ### Scheduling ManagedPromise Callbacks <a id="scheduling_callbacks"></a>
|
|
177
145
|
*
|
|
178
146
|
* How callbacks are scheduled in the control flow depends on when they are
|
|
179
147
|
* attached to the promise. Callbacks attached to a _previously_ resolved
|
|
@@ -463,18 +431,17 @@
|
|
|
463
431
|
*
|
|
464
432
|
* ES6 promises do not require users to handle a promise rejections. This can
|
|
465
433
|
* result in subtle bugs as the rejections are silently "swallowed" by the
|
|
466
|
-
*
|
|
434
|
+
* ManagedPromise class.
|
|
467
435
|
*
|
|
468
|
-
*
|
|
436
|
+
* ManagedPromise.reject(Error('boom'));
|
|
469
437
|
* // ... *crickets* ...
|
|
470
438
|
*
|
|
471
|
-
* Selenium's
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* will propagate up the stack.
|
|
439
|
+
* Selenium's promise module, on the other hand, requires that every rejection
|
|
440
|
+
* be explicitly handled. When a {@linkplain ManagedPromise ManagedPromise} is
|
|
441
|
+
* rejected and no callbacks are defined on that promise, it is considered an
|
|
442
|
+
* _unhandled rejection_ and reproted to the active task queue. If the rejection
|
|
443
|
+
* remains unhandled after a single turn of the [event loop][JSEL] (scheduled
|
|
444
|
+
* with a micro-task), it will propagate up the stack.
|
|
478
445
|
*
|
|
479
446
|
* ## Error Propagation
|
|
480
447
|
*
|
|
@@ -485,7 +452,7 @@
|
|
|
485
452
|
* // No callbacks registered on promise -> unhandled rejection
|
|
486
453
|
* promise.rejected(Error('boom'));
|
|
487
454
|
* flow.execute(function() { console.log('this will never run'); });
|
|
488
|
-
* }).
|
|
455
|
+
* }).catch(function(e) {
|
|
489
456
|
* console.log(e.message);
|
|
490
457
|
* });
|
|
491
458
|
* // boom
|
|
@@ -497,7 +464,7 @@
|
|
|
497
464
|
* promise.rejected(Error('boom'));
|
|
498
465
|
* flow.execute(function() { console.log('a'); }).
|
|
499
466
|
* then(function() { console.log('b'); });
|
|
500
|
-
* }).
|
|
467
|
+
* }).catch(function(e) {
|
|
501
468
|
* console.log(e.message);
|
|
502
469
|
* });
|
|
503
470
|
* // boom
|
|
@@ -508,21 +475,20 @@
|
|
|
508
475
|
* flow.execute(function() {
|
|
509
476
|
* promise.rejected(Error('boom'));
|
|
510
477
|
* return flow.execute(someOtherTask);
|
|
511
|
-
* }).
|
|
478
|
+
* }).catch(function(e) {
|
|
512
479
|
* console.log(e.message);
|
|
513
480
|
* });
|
|
514
481
|
* // boom
|
|
515
482
|
*
|
|
516
483
|
* If there are multiple unhandled rejections within a task, they are packaged
|
|
517
|
-
* in a {@link
|
|
518
|
-
*
|
|
519
|
-
* `Set` of the recorded unhandled rejections:
|
|
484
|
+
* in a {@link MultipleUnhandledRejectionError}, which has an `errors` property
|
|
485
|
+
* that is a `Set` of the recorded unhandled rejections:
|
|
520
486
|
*
|
|
521
487
|
* flow.execute(function() {
|
|
522
488
|
* promise.rejected(Error('boom1'));
|
|
523
489
|
* promise.rejected(Error('boom2'));
|
|
524
|
-
* }).
|
|
525
|
-
* console.log(ex instanceof
|
|
490
|
+
* }).catch(function(ex) {
|
|
491
|
+
* console.log(ex instanceof MultipleUnhandledRejectionError);
|
|
526
492
|
* for (var e of ex.errors) {
|
|
527
493
|
* console.log(e.message);
|
|
528
494
|
* }
|
|
@@ -542,7 +508,7 @@
|
|
|
542
508
|
* flow.execute(function() {
|
|
543
509
|
* promise.rejected(Error('boom'));
|
|
544
510
|
* subTask = flow.execute(function() {});
|
|
545
|
-
* }).
|
|
511
|
+
* }).catch(function(e) {
|
|
546
512
|
* console.log(e.message);
|
|
547
513
|
* }).then(function() {
|
|
548
514
|
* return subTask.then(
|
|
@@ -564,7 +530,7 @@
|
|
|
564
530
|
* throw Error('fail!');
|
|
565
531
|
* });
|
|
566
532
|
* });
|
|
567
|
-
* }).
|
|
533
|
+
* }).catch(function(e) {
|
|
568
534
|
* console.log(e.message);
|
|
569
535
|
* });
|
|
570
536
|
* // fail!
|
|
@@ -580,9 +546,9 @@
|
|
|
580
546
|
*
|
|
581
547
|
* Bottom line: you __*must*__ handle rejected promises.
|
|
582
548
|
*
|
|
583
|
-
* #
|
|
549
|
+
* # ManagedPromise/A+ Compatibility
|
|
584
550
|
*
|
|
585
|
-
* This `promise` module is compliant with the [
|
|
551
|
+
* This `promise` module is compliant with the [ManagedPromise/A+][] specification
|
|
586
552
|
* except for sections `2.2.6.1` and `2.2.6.2`:
|
|
587
553
|
*
|
|
588
554
|
* >
|
|
@@ -596,7 +562,7 @@
|
|
|
596
562
|
* Specifically, the conformance tests contains the following scenario (for
|
|
597
563
|
* brevity, only the fulfillment version is shown):
|
|
598
564
|
*
|
|
599
|
-
* var p1 =
|
|
565
|
+
* var p1 = ManagedPromise.resolve();
|
|
600
566
|
* p1.then(function() {
|
|
601
567
|
* console.log('A');
|
|
602
568
|
* p1.then(() => console.log('B'));
|
|
@@ -621,36 +587,73 @@
|
|
|
621
587
|
*
|
|
622
588
|
* [JSEL]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
|
|
623
589
|
* [GF]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
|
|
624
|
-
* [
|
|
590
|
+
* [ManagedPromise/A+]: https://promisesaplus.com/
|
|
625
591
|
*/
|
|
626
592
|
|
|
627
|
-
|
|
628
|
-
goog.module.declareLegacyNamespace();
|
|
593
|
+
'use strict';
|
|
629
594
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
var asyncRun = goog.require('goog.async.run');
|
|
633
|
-
var throwException = goog.require('goog.async.throwException');
|
|
634
|
-
var DebugError = goog.require('goog.debug.Error');
|
|
635
|
-
var log = goog.require('goog.log');
|
|
636
|
-
var Objects = goog.require('goog.object');
|
|
637
|
-
var EventEmitter = goog.require('webdriver.EventEmitter');
|
|
638
|
-
var stacktrace = goog.require('webdriver.stacktrace');
|
|
595
|
+
const events = require('./events');
|
|
596
|
+
const logging = require('./logging');
|
|
639
597
|
|
|
640
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Alias to help with readability and differentiate types.
|
|
601
|
+
* @const
|
|
602
|
+
*/
|
|
603
|
+
const NativePromise = Promise;
|
|
604
|
+
|
|
641
605
|
|
|
642
606
|
/**
|
|
643
|
-
*
|
|
644
|
-
*
|
|
607
|
+
* Whether to append traces of `then` to rejection errors.
|
|
608
|
+
* @type {boolean}
|
|
645
609
|
*/
|
|
646
|
-
|
|
610
|
+
var LONG_STACK_TRACES = false; // TODO: this should not be CONSTANT_CASE
|
|
611
|
+
|
|
647
612
|
|
|
648
613
|
/** @const */
|
|
649
|
-
|
|
614
|
+
const LOG = logging.getLogger('promise');
|
|
650
615
|
|
|
651
616
|
|
|
652
|
-
|
|
653
|
-
|
|
617
|
+
const UNIQUE_IDS = new WeakMap;
|
|
618
|
+
let nextId = 1;
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
function getUid(obj) {
|
|
622
|
+
let id = UNIQUE_IDS.get(obj);
|
|
623
|
+
if (!id) {
|
|
624
|
+
id = nextId;
|
|
625
|
+
nextId += 1;
|
|
626
|
+
UNIQUE_IDS.set(obj, id);
|
|
627
|
+
}
|
|
628
|
+
return id;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Runs the given function after a micro-task yield.
|
|
634
|
+
* @param {function()} fn The function to run.
|
|
635
|
+
*/
|
|
636
|
+
function asyncRun(fn) {
|
|
637
|
+
NativePromise.resolve().then(function() {
|
|
638
|
+
try {
|
|
639
|
+
fn();
|
|
640
|
+
} catch (ignored) {
|
|
641
|
+
// Do nothing.
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Throws an error asynchronously so it is reported to the global error handler.
|
|
649
|
+
*
|
|
650
|
+
* @param {!Error} error The error to throw.
|
|
651
|
+
*/
|
|
652
|
+
function asyncThrow(error) {
|
|
653
|
+
setTimeout(function() {
|
|
654
|
+
throw error;
|
|
655
|
+
}, 0);
|
|
656
|
+
}
|
|
654
657
|
|
|
655
658
|
|
|
656
659
|
/**
|
|
@@ -661,18 +664,18 @@ var LOG = log.getLogger('webdriver.promise');
|
|
|
661
664
|
* @template T
|
|
662
665
|
*/
|
|
663
666
|
function vlog(level, loggable, opt_self) {
|
|
664
|
-
var logLevel =
|
|
667
|
+
var logLevel = logging.Level.FINE;
|
|
665
668
|
if (level > 1) {
|
|
666
|
-
logLevel =
|
|
669
|
+
logLevel = logging.Level.FINEST;
|
|
667
670
|
} else if (level > 0) {
|
|
668
|
-
logLevel =
|
|
671
|
+
logLevel = logging.Level.FINER;
|
|
669
672
|
}
|
|
670
673
|
|
|
671
674
|
if (typeof loggable === 'function') {
|
|
672
675
|
loggable = loggable.bind(opt_self);
|
|
673
676
|
}
|
|
674
677
|
|
|
675
|
-
|
|
678
|
+
LOG.log(logLevel, loggable);
|
|
676
679
|
}
|
|
677
680
|
|
|
678
681
|
|
|
@@ -680,150 +683,134 @@ function vlog(level, loggable, opt_self) {
|
|
|
680
683
|
* Generates an error to capture the current stack trace.
|
|
681
684
|
* @param {string} name Error name for this stack trace.
|
|
682
685
|
* @param {string} msg Message to record.
|
|
683
|
-
* @param {
|
|
684
|
-
* stack; only applicable in V8.
|
|
686
|
+
* @param {Function=} opt_topFn The function that should appear at the top of
|
|
687
|
+
* the stack; only applicable in V8.
|
|
685
688
|
* @return {!Error} The generated error.
|
|
686
689
|
*/
|
|
687
|
-
|
|
690
|
+
function captureStackTrace(name, msg, opt_topFn) {
|
|
688
691
|
var e = Error(msg);
|
|
689
692
|
e.name = name;
|
|
690
693
|
if (Error.captureStackTrace) {
|
|
691
|
-
Error.captureStackTrace(e,
|
|
694
|
+
Error.captureStackTrace(e, opt_topFn);
|
|
692
695
|
} else {
|
|
693
|
-
var stack =
|
|
694
|
-
e.stack = e.toString();
|
|
696
|
+
var stack = Error().stack;
|
|
695
697
|
if (stack) {
|
|
698
|
+
e.stack = e.toString();
|
|
696
699
|
e.stack += '\n' + stack;
|
|
697
700
|
}
|
|
698
701
|
}
|
|
699
702
|
return e;
|
|
700
|
-
}
|
|
703
|
+
}
|
|
701
704
|
|
|
702
705
|
|
|
703
706
|
/**
|
|
704
707
|
* Error used when the computation of a promise is cancelled.
|
|
705
|
-
*
|
|
706
|
-
* @unrestricted
|
|
707
708
|
*/
|
|
708
|
-
|
|
709
|
+
class CancellationError extends Error {
|
|
709
710
|
/**
|
|
710
711
|
* @param {string=} opt_msg The cancellation message.
|
|
711
712
|
*/
|
|
712
|
-
constructor
|
|
713
|
-
|
|
713
|
+
constructor(opt_msg) {
|
|
714
|
+
super(opt_msg);
|
|
714
715
|
|
|
715
716
|
/** @override */
|
|
716
|
-
this.name =
|
|
717
|
+
this.name = this.constructor.name;
|
|
717
718
|
|
|
718
719
|
/** @private {boolean} */
|
|
719
720
|
this.silent_ = false;
|
|
720
|
-
}
|
|
721
|
+
}
|
|
721
722
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
message = opt_msg;
|
|
737
|
-
if (error) {
|
|
738
|
-
message += ': ' + error;
|
|
739
|
-
}
|
|
740
|
-
return new promise.CancellationError(message);
|
|
741
|
-
}
|
|
723
|
+
/**
|
|
724
|
+
* Wraps the given error in a CancellationError.
|
|
725
|
+
*
|
|
726
|
+
* @param {*} error The error to wrap.
|
|
727
|
+
* @param {string=} opt_msg The prefix message to use.
|
|
728
|
+
* @return {!CancellationError} A cancellation error.
|
|
729
|
+
*/
|
|
730
|
+
static wrap(error, opt_msg) {
|
|
731
|
+
var message;
|
|
732
|
+
if (error instanceof CancellationError) {
|
|
733
|
+
return new CancellationError(
|
|
734
|
+
opt_msg ? (opt_msg + ': ' + error.message) : error.message);
|
|
735
|
+
} else if (opt_msg) {
|
|
736
|
+
message = opt_msg;
|
|
742
737
|
if (error) {
|
|
743
|
-
message
|
|
738
|
+
message += ': ' + error;
|
|
744
739
|
}
|
|
745
|
-
return new
|
|
740
|
+
return new CancellationError(message);
|
|
746
741
|
}
|
|
742
|
+
if (error) {
|
|
743
|
+
message = error + '';
|
|
744
|
+
}
|
|
745
|
+
return new CancellationError(message);
|
|
747
746
|
}
|
|
748
|
-
}
|
|
747
|
+
}
|
|
749
748
|
|
|
750
749
|
|
|
751
750
|
/**
|
|
752
751
|
* Error used to cancel tasks when a control flow is reset.
|
|
753
|
-
* @unrestricted
|
|
754
752
|
* @final
|
|
755
753
|
*/
|
|
756
|
-
|
|
757
|
-
constructor
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
/** @override */
|
|
761
|
-
this.name = 'FlowResetError';
|
|
762
|
-
|
|
754
|
+
class FlowResetError extends CancellationError {
|
|
755
|
+
constructor() {
|
|
756
|
+
super('ControlFlow was reset');
|
|
763
757
|
this.silent_ = true;
|
|
764
758
|
}
|
|
765
|
-
}
|
|
759
|
+
}
|
|
766
760
|
|
|
767
761
|
|
|
768
762
|
/**
|
|
769
763
|
* Error used to cancel tasks that have been discarded due to an uncaught error
|
|
770
764
|
* reported earlier in the control flow.
|
|
771
|
-
* @unrestricted
|
|
772
765
|
* @final
|
|
773
766
|
*/
|
|
774
|
-
|
|
767
|
+
class DiscardedTaskError extends CancellationError {
|
|
775
768
|
/** @param {*} error The original error. */
|
|
776
|
-
constructor
|
|
769
|
+
constructor(error) {
|
|
777
770
|
if (error instanceof DiscardedTaskError) {
|
|
778
771
|
return /** @type {!DiscardedTaskError} */(error);
|
|
779
772
|
}
|
|
780
773
|
|
|
781
774
|
var msg = '';
|
|
782
775
|
if (error) {
|
|
783
|
-
msg = ': ' + (
|
|
776
|
+
msg = ': ' + (
|
|
777
|
+
typeof error.message === 'string' ? error.message : error);
|
|
784
778
|
}
|
|
785
779
|
|
|
786
|
-
|
|
787
|
-
'Task was discarded due to a previous failure' + msg);
|
|
788
|
-
|
|
789
|
-
/** @override */
|
|
790
|
-
this.name = 'DiscardedTaskError';
|
|
780
|
+
super('Task was discarded due to a previous failure' + msg);
|
|
791
781
|
this.silent_ = true;
|
|
792
782
|
}
|
|
793
|
-
}
|
|
783
|
+
}
|
|
794
784
|
|
|
795
785
|
|
|
796
786
|
/**
|
|
797
787
|
* Error used when there are multiple unhandled promise rejections detected
|
|
798
788
|
* within a task or callback.
|
|
799
789
|
*
|
|
800
|
-
* @unrestricted
|
|
801
790
|
* @final
|
|
802
791
|
*/
|
|
803
|
-
|
|
792
|
+
class MultipleUnhandledRejectionError extends Error {
|
|
804
793
|
/**
|
|
805
794
|
* @param {!(Set<*>)} errors The errors to report.
|
|
806
795
|
*/
|
|
807
|
-
constructor
|
|
808
|
-
promise
|
|
809
|
-
this, 'constructor', 'Multiple unhandled promise rejections reported');
|
|
796
|
+
constructor(errors) {
|
|
797
|
+
super('Multiple unhandled promise rejections reported');
|
|
810
798
|
|
|
811
799
|
/** @override */
|
|
812
|
-
this.name =
|
|
800
|
+
this.name = this.constructor.name;
|
|
813
801
|
|
|
814
802
|
/** @type {!Set<*>} */
|
|
815
803
|
this.errors = errors;
|
|
816
804
|
}
|
|
817
|
-
}
|
|
805
|
+
}
|
|
818
806
|
|
|
819
807
|
|
|
820
808
|
/**
|
|
821
809
|
* Property used to flag constructor's as implementing the Thenable interface
|
|
822
810
|
* for runtime type checking.
|
|
823
|
-
* @type {string}
|
|
824
811
|
* @const
|
|
825
812
|
*/
|
|
826
|
-
|
|
813
|
+
const IMPLEMENTED_BY_SYMBOL = Symbol('promise.Thenable');
|
|
827
814
|
|
|
828
815
|
|
|
829
816
|
/**
|
|
@@ -834,64 +821,54 @@ var IMPLEMENTED_BY_PROP = '$webdriver_Thenable';
|
|
|
834
821
|
* @extends {IThenable<T>}
|
|
835
822
|
* @template T
|
|
836
823
|
*/
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
ctor.prototype[
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
ctor.prototype,
|
|
855
|
-
IMPLEMENTED_BY_PROP,
|
|
856
|
-
{'value': true, 'enumerable': false});
|
|
857
|
-
} catch (ex) {
|
|
858
|
-
ctor.prototype[IMPLEMENTED_BY_PROP] = true;
|
|
859
|
-
}
|
|
860
|
-
},
|
|
824
|
+
class Thenable {
|
|
825
|
+
/**
|
|
826
|
+
* Adds a property to a class prototype to allow runtime checks of whether
|
|
827
|
+
* instances of that class implement the Thenable interface. This function
|
|
828
|
+
* will also ensure the prototype's {@code then} function is exported from
|
|
829
|
+
* compiled code.
|
|
830
|
+
* @param {function(new: Thenable, ...?)} ctor The
|
|
831
|
+
* constructor whose prototype to modify.
|
|
832
|
+
*/
|
|
833
|
+
static addImplementation(ctor) {
|
|
834
|
+
ctor.prototype['then'] = ctor.prototype.then;
|
|
835
|
+
try {
|
|
836
|
+
ctor.prototype[IMPLEMENTED_BY_SYMBOL] = true;
|
|
837
|
+
} catch (ignored) {
|
|
838
|
+
// Property access denied?
|
|
839
|
+
}
|
|
840
|
+
}
|
|
861
841
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
if (!object) {
|
|
873
|
-
return false;
|
|
874
|
-
}
|
|
875
|
-
try {
|
|
876
|
-
return !!object[IMPLEMENTED_BY_PROP];
|
|
877
|
-
} catch (e) {
|
|
878
|
-
return false; // Property access seems to be forbidden.
|
|
879
|
-
}
|
|
842
|
+
/**
|
|
843
|
+
* Checks if an object has been tagged for implementing the Thenable
|
|
844
|
+
* interface as defined by {@link Thenable.addImplementation}.
|
|
845
|
+
* @param {*} object The object to test.
|
|
846
|
+
* @return {boolean} Whether the object is an implementation of the Thenable
|
|
847
|
+
* interface.
|
|
848
|
+
*/
|
|
849
|
+
static isImplementation(object) {
|
|
850
|
+
if (!object) {
|
|
851
|
+
return false;
|
|
880
852
|
}
|
|
881
|
-
|
|
853
|
+
try {
|
|
854
|
+
return !!object[IMPLEMENTED_BY_SYMBOL];
|
|
855
|
+
} catch (e) {
|
|
856
|
+
return false; // Property access seems to be forbidden.
|
|
857
|
+
}
|
|
858
|
+
}
|
|
882
859
|
|
|
883
860
|
/**
|
|
884
861
|
* Cancels the computation of this promise's value, rejecting the promise in
|
|
885
862
|
* the process. This method is a no-op if the promise has already been
|
|
886
863
|
* resolved.
|
|
887
864
|
*
|
|
888
|
-
* @param {(string|
|
|
889
|
-
*
|
|
865
|
+
* @param {(string|Error)=} opt_reason The reason this promise is being
|
|
866
|
+
* cancelled. This value will be wrapped in a {@link CancellationError}.
|
|
890
867
|
*/
|
|
891
|
-
cancel
|
|
868
|
+
cancel(opt_reason) {}
|
|
892
869
|
|
|
893
870
|
/** @return {boolean} Whether this promise's value is still being computed. */
|
|
894
|
-
isPending
|
|
871
|
+
isPending() {}
|
|
895
872
|
|
|
896
873
|
/**
|
|
897
874
|
* Registers listeners for when this instance is resolved.
|
|
@@ -902,11 +879,11 @@ promise.Thenable = goog.defineClass(null, {
|
|
|
902
879
|
* @param {?(function(*): (R|IThenable<R>))=} opt_errback
|
|
903
880
|
* The function to call if this promise is rejected. The function should
|
|
904
881
|
* expect a single argument: the rejection reason.
|
|
905
|
-
* @return {!
|
|
882
|
+
* @return {!ManagedPromise<R>} A new promise which will be
|
|
906
883
|
* resolved with the result of the invoked callback.
|
|
907
884
|
* @template R
|
|
908
885
|
*/
|
|
909
|
-
then
|
|
886
|
+
then(opt_callback, opt_errback) {}
|
|
910
887
|
|
|
911
888
|
/**
|
|
912
889
|
* Registers a listener for when this promise is rejected. This is synonymous
|
|
@@ -920,18 +897,69 @@ promise.Thenable = goog.defineClass(null, {
|
|
|
920
897
|
* }
|
|
921
898
|
*
|
|
922
899
|
* // Asynchronous promise API:
|
|
923
|
-
* doAsynchronousWork().
|
|
900
|
+
* doAsynchronousWork().catch(function(ex) {
|
|
924
901
|
* console.error(ex);
|
|
925
902
|
* });
|
|
926
903
|
*
|
|
927
904
|
* @param {function(*): (R|IThenable<R>)} errback The
|
|
928
905
|
* function to call if this promise is rejected. The function should
|
|
929
906
|
* expect a single argument: the rejection reason.
|
|
930
|
-
* @return {!
|
|
907
|
+
* @return {!ManagedPromise<R>} A new promise which will be
|
|
931
908
|
* resolved with the result of the invoked callback.
|
|
932
909
|
* @template R
|
|
933
910
|
*/
|
|
934
|
-
|
|
911
|
+
catch(errback) {}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* An alias for {@link #catch()}
|
|
915
|
+
*
|
|
916
|
+
* @param {function(*): (R|IThenable<R>)} errback The
|
|
917
|
+
* function to call if this promise is rejected. The function should
|
|
918
|
+
* expect a single argument: the rejection reason.
|
|
919
|
+
* @return {!ManagedPromise<R>} A new promise which will be
|
|
920
|
+
* resolved wdith the result of the invoked callback.
|
|
921
|
+
* @deprecated Use {@link #catch()} instead.
|
|
922
|
+
* @template R
|
|
923
|
+
*/
|
|
924
|
+
thenCatch(errback) {}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Registers a listener to invoke when this promise is resolved, regardless
|
|
928
|
+
* of whether the promise's value was successfully computed. This function
|
|
929
|
+
* is synonymous with the {@code finally} clause in a synchronous API:
|
|
930
|
+
*
|
|
931
|
+
* // Synchronous API:
|
|
932
|
+
* try {
|
|
933
|
+
* doSynchronousWork();
|
|
934
|
+
* } finally {
|
|
935
|
+
* cleanUp();
|
|
936
|
+
* }
|
|
937
|
+
*
|
|
938
|
+
* // Asynchronous promise API:
|
|
939
|
+
* doAsynchronousWork().finally(cleanUp);
|
|
940
|
+
*
|
|
941
|
+
* __Note:__ similar to the {@code finally} clause, if the registered
|
|
942
|
+
* callback returns a rejected promise or throws an error, it will silently
|
|
943
|
+
* replace the rejection error (if any) from this promise:
|
|
944
|
+
*
|
|
945
|
+
* try {
|
|
946
|
+
* throw Error('one');
|
|
947
|
+
* } finally {
|
|
948
|
+
* throw Error('two'); // Hides Error: one
|
|
949
|
+
* }
|
|
950
|
+
*
|
|
951
|
+
* promise.rejected(Error('one'))
|
|
952
|
+
* .finally(function() {
|
|
953
|
+
* throw Error('two'); // Hides Error: one
|
|
954
|
+
* });
|
|
955
|
+
*
|
|
956
|
+
* @param {function(): (R|IThenable<R>)} callback The function to call when
|
|
957
|
+
* this promise is resolved.
|
|
958
|
+
* @return {!ManagedPromise<R>} A promise that will be fulfilled
|
|
959
|
+
* with the callback result.
|
|
960
|
+
* @template R
|
|
961
|
+
*/
|
|
962
|
+
finally(callback) {}
|
|
935
963
|
|
|
936
964
|
/**
|
|
937
965
|
* Registers a listener to invoke when this promise is resolved, regardless
|
|
@@ -965,19 +993,18 @@ promise.Thenable = goog.defineClass(null, {
|
|
|
965
993
|
*
|
|
966
994
|
* @param {function(): (R|IThenable<R>)} callback The function
|
|
967
995
|
* to call when this promise is resolved.
|
|
968
|
-
* @return {!
|
|
996
|
+
* @return {!ManagedPromise<R>} A promise that will be fulfilled
|
|
969
997
|
* with the callback result.
|
|
998
|
+
* @deprecated Use {@link #finally()} instead.
|
|
970
999
|
* @template R
|
|
971
1000
|
*/
|
|
972
|
-
thenFinally
|
|
973
|
-
});
|
|
974
|
-
|
|
1001
|
+
thenFinally(callback) {}}
|
|
975
1002
|
|
|
976
1003
|
|
|
977
1004
|
/**
|
|
978
1005
|
* @enum {string}
|
|
979
1006
|
*/
|
|
980
|
-
|
|
1007
|
+
const PromiseState = {
|
|
981
1008
|
PENDING: 'pending',
|
|
982
1009
|
BLOCKED: 'blocked',
|
|
983
1010
|
REJECTED: 'rejected',
|
|
@@ -987,11 +1014,11 @@ var PromiseState = {
|
|
|
987
1014
|
|
|
988
1015
|
/**
|
|
989
1016
|
* Internal symbol used to store a cancellation handler for
|
|
990
|
-
* {@link
|
|
1017
|
+
* {@link ManagedPromise} objects. This is an internal implementation detail
|
|
991
1018
|
* used by the {@link TaskQueue} class to monitor for when a promise is
|
|
992
1019
|
* cancelled without generating an extra promise via then().
|
|
993
1020
|
*/
|
|
994
|
-
|
|
1021
|
+
const CANCEL_HANDLER_SYMBOL = Symbol('on cancel');
|
|
995
1022
|
|
|
996
1023
|
|
|
997
1024
|
/**
|
|
@@ -1001,12 +1028,12 @@ var CANCEL_HANDLER_SYMBOL = Symbol('on cancel');
|
|
|
1001
1028
|
* fulfilled or rejected state, at which point the promise is considered
|
|
1002
1029
|
* resolved.
|
|
1003
1030
|
*
|
|
1004
|
-
* @implements {
|
|
1031
|
+
* @implements {Thenable<T>}
|
|
1032
|
+
* @unrestricted
|
|
1005
1033
|
* @template T
|
|
1006
1034
|
* @see http://promises-aplus.github.io/promises-spec/
|
|
1007
|
-
* @unrestricted // For using CANCEL_HANDLER_SYMBOL.
|
|
1008
1035
|
*/
|
|
1009
|
-
|
|
1036
|
+
class ManagedPromise {
|
|
1010
1037
|
/**
|
|
1011
1038
|
* @param {function(
|
|
1012
1039
|
* function((T|IThenable<T>|Thenable)=),
|
|
@@ -1014,23 +1041,22 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1014
1041
|
* Function that is invoked immediately to begin computation of this
|
|
1015
1042
|
* promise's value. The function should accept a pair of callback
|
|
1016
1043
|
* functions, one for fulfilling the promise and another for rejecting it.
|
|
1017
|
-
* @param {
|
|
1044
|
+
* @param {ControlFlow=} opt_flow The control flow
|
|
1018
1045
|
* this instance was created under. Defaults to the currently active flow.
|
|
1019
1046
|
*/
|
|
1020
|
-
constructor
|
|
1021
|
-
|
|
1047
|
+
constructor(resolver, opt_flow) {
|
|
1048
|
+
getUid(this);
|
|
1022
1049
|
|
|
1023
|
-
/** @private {!
|
|
1024
|
-
this.flow_ = opt_flow ||
|
|
1050
|
+
/** @private {!ControlFlow} */
|
|
1051
|
+
this.flow_ = opt_flow || controlFlow();
|
|
1025
1052
|
|
|
1026
1053
|
/** @private {Error} */
|
|
1027
1054
|
this.stack_ = null;
|
|
1028
|
-
if (
|
|
1029
|
-
this.stack_ =
|
|
1030
|
-
'Promise', 'new', promise.Promise);
|
|
1055
|
+
if (LONG_STACK_TRACES) {
|
|
1056
|
+
this.stack_ = captureStackTrace('ManagedPromise', 'new', this.constructor);
|
|
1031
1057
|
}
|
|
1032
1058
|
|
|
1033
|
-
/** @private {
|
|
1059
|
+
/** @private {ManagedPromise<?>} */
|
|
1034
1060
|
this.parent_ = null;
|
|
1035
1061
|
|
|
1036
1062
|
/** @private {Array<!Task>} */
|
|
@@ -1048,7 +1074,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1048
1074
|
/** @private {TaskQueue} */
|
|
1049
1075
|
this.queue_ = null;
|
|
1050
1076
|
|
|
1051
|
-
/** @private {(function(
|
|
1077
|
+
/** @private {(function(CancellationError)|null)} */
|
|
1052
1078
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
1053
1079
|
|
|
1054
1080
|
try {
|
|
@@ -1061,13 +1087,13 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1061
1087
|
} catch (ex) {
|
|
1062
1088
|
this.resolve_(PromiseState.REJECTED, ex);
|
|
1063
1089
|
}
|
|
1064
|
-
}
|
|
1090
|
+
}
|
|
1065
1091
|
|
|
1066
1092
|
/** @override */
|
|
1067
|
-
toString
|
|
1068
|
-
return '
|
|
1093
|
+
toString() {
|
|
1094
|
+
return 'ManagedPromise::' + getUid(this) +
|
|
1069
1095
|
' {[[PromiseStatus]]: "' + this.state_ + '"}';
|
|
1070
|
-
}
|
|
1096
|
+
}
|
|
1071
1097
|
|
|
1072
1098
|
/**
|
|
1073
1099
|
* Resolves this promise. If the new value is itself a promise, this function
|
|
@@ -1077,7 +1103,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1077
1103
|
* @throws {TypeError} If {@code newValue === this}.
|
|
1078
1104
|
* @private
|
|
1079
1105
|
*/
|
|
1080
|
-
resolve_
|
|
1106
|
+
resolve_(newState, newValue) {
|
|
1081
1107
|
if (PromiseState.PENDING !== this.state_) {
|
|
1082
1108
|
return;
|
|
1083
1109
|
}
|
|
@@ -1093,15 +1119,16 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1093
1119
|
this.state_ = PromiseState.BLOCKED;
|
|
1094
1120
|
|
|
1095
1121
|
if (newState !== PromiseState.REJECTED) {
|
|
1096
|
-
if (
|
|
1122
|
+
if (Thenable.isImplementation(newValue)) {
|
|
1097
1123
|
// 2.3.2
|
|
1098
|
-
newValue = /** @type {!
|
|
1124
|
+
newValue = /** @type {!Thenable} */(newValue);
|
|
1099
1125
|
newValue.then(
|
|
1100
1126
|
this.unblockAndResolve_.bind(this, PromiseState.FULFILLED),
|
|
1101
1127
|
this.unblockAndResolve_.bind(this, PromiseState.REJECTED));
|
|
1102
1128
|
return;
|
|
1103
1129
|
|
|
1104
|
-
} else if (
|
|
1130
|
+
} else if (newValue
|
|
1131
|
+
&& (typeof newValue === 'object' || typeof newValue === 'function')) {
|
|
1105
1132
|
// 2.3.3
|
|
1106
1133
|
|
|
1107
1134
|
try {
|
|
@@ -1115,10 +1142,9 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1115
1142
|
return;
|
|
1116
1143
|
}
|
|
1117
1144
|
|
|
1118
|
-
// NB: goog.isFunction is loose and will accept instanceof Function.
|
|
1119
1145
|
if (typeof then === 'function') {
|
|
1120
1146
|
// 2.3.3.3
|
|
1121
|
-
this.invokeThen_(newValue, then);
|
|
1147
|
+
this.invokeThen_(/** @type {!Object} */(newValue), then);
|
|
1122
1148
|
return;
|
|
1123
1149
|
}
|
|
1124
1150
|
}
|
|
@@ -1133,7 +1159,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1133
1159
|
this.state_ = newState;
|
|
1134
1160
|
this.value_ = newValue;
|
|
1135
1161
|
this.scheduleNotifications_();
|
|
1136
|
-
}
|
|
1162
|
+
}
|
|
1137
1163
|
|
|
1138
1164
|
/**
|
|
1139
1165
|
* Invokes a thenable's "then" method according to 2.3.3.3 of the promise
|
|
@@ -1142,7 +1168,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1142
1168
|
* @param {!Function} then The "then" function to invoke.
|
|
1143
1169
|
* @private
|
|
1144
1170
|
*/
|
|
1145
|
-
invokeThen_
|
|
1171
|
+
invokeThen_(x, then) {
|
|
1146
1172
|
var called = false;
|
|
1147
1173
|
var self = this;
|
|
1148
1174
|
|
|
@@ -1169,28 +1195,28 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1169
1195
|
// 2.3.3.3.4.2
|
|
1170
1196
|
rejectPromise(e);
|
|
1171
1197
|
}
|
|
1172
|
-
}
|
|
1198
|
+
}
|
|
1173
1199
|
|
|
1174
1200
|
/**
|
|
1175
1201
|
* @param {PromiseState} newState The promise's new state.
|
|
1176
1202
|
* @param {*} newValue The promise's new value.
|
|
1177
1203
|
* @private
|
|
1178
1204
|
*/
|
|
1179
|
-
unblockAndResolve_
|
|
1205
|
+
unblockAndResolve_(newState, newValue) {
|
|
1180
1206
|
if (this.state_ === PromiseState.BLOCKED) {
|
|
1181
1207
|
this.state_ = PromiseState.PENDING;
|
|
1182
1208
|
this.resolve_(newState, newValue);
|
|
1183
1209
|
}
|
|
1184
|
-
}
|
|
1210
|
+
}
|
|
1185
1211
|
|
|
1186
1212
|
/**
|
|
1187
1213
|
* @private
|
|
1188
1214
|
*/
|
|
1189
|
-
scheduleNotifications_
|
|
1215
|
+
scheduleNotifications_() {
|
|
1190
1216
|
vlog(2, () => this + ' scheduling notifications', this);
|
|
1191
1217
|
|
|
1192
1218
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
1193
|
-
if (this.value_ instanceof
|
|
1219
|
+
if (this.value_ instanceof CancellationError
|
|
1194
1220
|
&& this.value_.silent_) {
|
|
1195
1221
|
this.callbacks_ = null;
|
|
1196
1222
|
}
|
|
@@ -1201,14 +1227,14 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1201
1227
|
|
|
1202
1228
|
if (!this.handled_ &&
|
|
1203
1229
|
this.state_ === PromiseState.REJECTED &&
|
|
1204
|
-
!(this.value_ instanceof
|
|
1230
|
+
!(this.value_ instanceof CancellationError)) {
|
|
1205
1231
|
this.queue_.addUnhandledRejection(this);
|
|
1206
1232
|
}
|
|
1207
1233
|
this.queue_.scheduleCallbacks(this);
|
|
1208
|
-
}
|
|
1234
|
+
}
|
|
1209
1235
|
|
|
1210
1236
|
/** @override */
|
|
1211
|
-
cancel
|
|
1237
|
+
cancel(opt_reason) {
|
|
1212
1238
|
if (!canCancel(this)) {
|
|
1213
1239
|
return;
|
|
1214
1240
|
}
|
|
@@ -1216,7 +1242,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1216
1242
|
if (this.parent_ && canCancel(this.parent_)) {
|
|
1217
1243
|
this.parent_.cancel(opt_reason);
|
|
1218
1244
|
} else {
|
|
1219
|
-
var reason =
|
|
1245
|
+
var reason = CancellationError.wrap(opt_reason);
|
|
1220
1246
|
if (this[CANCEL_HANDLER_SYMBOL]) {
|
|
1221
1247
|
this[CANCEL_HANDLER_SYMBOL](reason);
|
|
1222
1248
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
@@ -1233,27 +1259,35 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1233
1259
|
return promise.state_ === PromiseState.PENDING
|
|
1234
1260
|
|| promise.state_ === PromiseState.BLOCKED;
|
|
1235
1261
|
}
|
|
1236
|
-
}
|
|
1262
|
+
}
|
|
1237
1263
|
|
|
1238
1264
|
/** @override */
|
|
1239
|
-
isPending
|
|
1265
|
+
isPending() {
|
|
1240
1266
|
return this.state_ === PromiseState.PENDING;
|
|
1241
|
-
}
|
|
1267
|
+
}
|
|
1242
1268
|
|
|
1243
1269
|
/** @override */
|
|
1244
|
-
then
|
|
1270
|
+
then(opt_callback, opt_errback) {
|
|
1245
1271
|
return this.addCallback_(
|
|
1246
|
-
opt_callback, opt_errback, 'then',
|
|
1247
|
-
}
|
|
1272
|
+
opt_callback, opt_errback, 'then', ManagedPromise.prototype.then);
|
|
1273
|
+
}
|
|
1248
1274
|
|
|
1249
1275
|
/** @override */
|
|
1250
|
-
|
|
1276
|
+
catch(errback) {
|
|
1251
1277
|
return this.addCallback_(
|
|
1252
|
-
null, errback, '
|
|
1253
|
-
}
|
|
1278
|
+
null, errback, 'catch', ManagedPromise.prototype.catch);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* @override
|
|
1283
|
+
* @deprecated Use {@link #catch()} instead.
|
|
1284
|
+
*/
|
|
1285
|
+
thenCatch(errback) {
|
|
1286
|
+
return this.catch(errback);
|
|
1287
|
+
}
|
|
1254
1288
|
|
|
1255
1289
|
/** @override */
|
|
1256
|
-
|
|
1290
|
+
finally(callback) {
|
|
1257
1291
|
var error;
|
|
1258
1292
|
var mustThrow = false;
|
|
1259
1293
|
return this.then(function() {
|
|
@@ -1267,7 +1301,15 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1267
1301
|
throw error;
|
|
1268
1302
|
}
|
|
1269
1303
|
});
|
|
1270
|
-
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* @override
|
|
1308
|
+
* @deprecated Use {@link #finally()} instead.
|
|
1309
|
+
*/
|
|
1310
|
+
thenFinally(callback) {
|
|
1311
|
+
return this.finally(callback);
|
|
1312
|
+
}
|
|
1271
1313
|
|
|
1272
1314
|
/**
|
|
1273
1315
|
* Registers a new callback with this promise
|
|
@@ -1278,13 +1320,13 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1278
1320
|
* @param {string} name The callback name.
|
|
1279
1321
|
* @param {!Function} fn The function to use as the top of the stack when
|
|
1280
1322
|
* recording the callback's creation point.
|
|
1281
|
-
* @return {!
|
|
1323
|
+
* @return {!ManagedPromise<R>} A new promise which will be resolved with the
|
|
1282
1324
|
* esult of the invoked callback.
|
|
1283
1325
|
* @template R
|
|
1284
1326
|
* @private
|
|
1285
1327
|
*/
|
|
1286
|
-
addCallback_
|
|
1287
|
-
if (
|
|
1328
|
+
addCallback_(callback, errback, name, fn) {
|
|
1329
|
+
if (typeof callback !== 'function' && typeof errback !== 'function') {
|
|
1288
1330
|
return this;
|
|
1289
1331
|
}
|
|
1290
1332
|
|
|
@@ -1297,7 +1339,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1297
1339
|
this.flow_,
|
|
1298
1340
|
this.invokeCallback_.bind(this, callback, errback),
|
|
1299
1341
|
name,
|
|
1300
|
-
|
|
1342
|
+
LONG_STACK_TRACES ? {name: 'Promise', top: fn} : undefined);
|
|
1301
1343
|
cb.promise.parent_ = this;
|
|
1302
1344
|
|
|
1303
1345
|
if (this.state_ !== PromiseState.PENDING &&
|
|
@@ -1313,7 +1355,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1313
1355
|
}
|
|
1314
1356
|
|
|
1315
1357
|
return cb.promise;
|
|
1316
|
-
}
|
|
1358
|
+
}
|
|
1317
1359
|
|
|
1318
1360
|
/**
|
|
1319
1361
|
* Invokes a callback function attached to this promise.
|
|
@@ -1324,15 +1366,15 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1324
1366
|
* @template R
|
|
1325
1367
|
* @private
|
|
1326
1368
|
*/
|
|
1327
|
-
invokeCallback_
|
|
1369
|
+
invokeCallback_(callback, errback) {
|
|
1328
1370
|
var callbackFn = callback;
|
|
1329
1371
|
if (this.state_ === PromiseState.REJECTED) {
|
|
1330
1372
|
callbackFn = errback;
|
|
1331
1373
|
}
|
|
1332
1374
|
|
|
1333
|
-
if (
|
|
1334
|
-
if (
|
|
1335
|
-
return
|
|
1375
|
+
if (typeof callbackFn === 'function') {
|
|
1376
|
+
if (isGenerator(callbackFn)) {
|
|
1377
|
+
return consume(callbackFn, null, this.value_);
|
|
1336
1378
|
}
|
|
1337
1379
|
return callbackFn(this.value_);
|
|
1338
1380
|
} else if (this.state_ === PromiseState.REJECTED) {
|
|
@@ -1341,34 +1383,34 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1341
1383
|
return this.value_;
|
|
1342
1384
|
}
|
|
1343
1385
|
}
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1386
|
+
}
|
|
1387
|
+
Thenable.addImplementation(ManagedPromise);
|
|
1346
1388
|
|
|
1347
1389
|
|
|
1348
1390
|
/**
|
|
1349
1391
|
* Represents a value that will be resolved at some point in the future. This
|
|
1350
|
-
* class represents the protected "producer" half of a
|
|
1392
|
+
* class represents the protected "producer" half of a ManagedPromise - each Deferred
|
|
1351
1393
|
* has a {@code promise} property that may be returned to consumers for
|
|
1352
1394
|
* registering callbacks, reserving the ability to resolve the deferred to the
|
|
1353
1395
|
* producer.
|
|
1354
1396
|
*
|
|
1355
1397
|
* If this Deferred is rejected and there are no listeners registered before
|
|
1356
1398
|
* the next turn of the event loop, the rejection will be passed to the
|
|
1357
|
-
* {@link
|
|
1399
|
+
* {@link ControlFlow} as an unhandled failure.
|
|
1358
1400
|
*
|
|
1359
|
-
* @implements {
|
|
1401
|
+
* @implements {Thenable<T>}
|
|
1360
1402
|
* @template T
|
|
1361
1403
|
*/
|
|
1362
|
-
|
|
1404
|
+
class Deferred {
|
|
1363
1405
|
/**
|
|
1364
|
-
* @param {
|
|
1406
|
+
* @param {ControlFlow=} opt_flow The control flow this instance was
|
|
1365
1407
|
* created under. This should only be provided during unit tests.
|
|
1366
1408
|
*/
|
|
1367
|
-
constructor
|
|
1409
|
+
constructor(opt_flow) {
|
|
1368
1410
|
var fulfill, reject;
|
|
1369
1411
|
|
|
1370
|
-
/** @type {!
|
|
1371
|
-
this.promise = new
|
|
1412
|
+
/** @type {!ManagedPromise<T>} */
|
|
1413
|
+
this.promise = new ManagedPromise(function(f, r) {
|
|
1372
1414
|
fulfill = f;
|
|
1373
1415
|
reject = r;
|
|
1374
1416
|
}, opt_flow);
|
|
@@ -1399,43 +1441,124 @@ promise.Deferred = goog.defineClass(null, {
|
|
|
1399
1441
|
checkNotSelf(opt_reason);
|
|
1400
1442
|
reject(opt_reason);
|
|
1401
1443
|
};
|
|
1402
|
-
}
|
|
1444
|
+
}
|
|
1403
1445
|
|
|
1404
1446
|
/** @override */
|
|
1405
|
-
isPending
|
|
1447
|
+
isPending() {
|
|
1406
1448
|
return this.promise.isPending();
|
|
1407
|
-
}
|
|
1449
|
+
}
|
|
1408
1450
|
|
|
1409
1451
|
/** @override */
|
|
1410
|
-
cancel
|
|
1452
|
+
cancel(opt_reason) {
|
|
1411
1453
|
this.promise.cancel(opt_reason);
|
|
1412
|
-
}
|
|
1454
|
+
}
|
|
1413
1455
|
|
|
1414
1456
|
/**
|
|
1415
1457
|
* @override
|
|
1416
1458
|
* @deprecated Use {@code then} from the promise property directly.
|
|
1417
1459
|
*/
|
|
1418
|
-
then
|
|
1460
|
+
then(opt_cb, opt_eb) {
|
|
1419
1461
|
return this.promise.then(opt_cb, opt_eb);
|
|
1420
|
-
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* @override
|
|
1466
|
+
* @deprecated Use {@lcode catch} from the promise property directly.
|
|
1467
|
+
*/
|
|
1468
|
+
catch(opt_eb) {
|
|
1469
|
+
return this.promise.catch(opt_eb);
|
|
1470
|
+
}
|
|
1421
1471
|
|
|
1422
1472
|
/**
|
|
1423
1473
|
* @override
|
|
1424
1474
|
* @deprecated Use {@code thenCatch} from the promise property directly.
|
|
1425
1475
|
*/
|
|
1426
|
-
thenCatch
|
|
1476
|
+
thenCatch(opt_eb) {
|
|
1427
1477
|
return this.promise.thenCatch(opt_eb);
|
|
1428
|
-
}
|
|
1478
|
+
}
|
|
1429
1479
|
|
|
1430
1480
|
/**
|
|
1431
1481
|
* @override
|
|
1432
1482
|
* @deprecated Use {@code thenFinally} from the promise property directly.
|
|
1433
1483
|
*/
|
|
1434
|
-
thenFinally
|
|
1484
|
+
thenFinally(opt_cb) {
|
|
1435
1485
|
return this.promise.thenFinally(opt_cb);
|
|
1436
1486
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* @override
|
|
1490
|
+
* @deprecated Use {@code finally} from the promise property directly.
|
|
1491
|
+
*/
|
|
1492
|
+
finally(opt_cb) {
|
|
1493
|
+
return this.promise.finally(opt_cb);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
Thenable.addImplementation(Deferred);
|
|
1497
|
+
|
|
1498
|
+
|
|
1499
|
+
/**
|
|
1500
|
+
* Registers a listener to invoke when a promise is resolved, regardless of
|
|
1501
|
+
* whether the promise's value was successfully computed. This function is
|
|
1502
|
+
* synonymous with the `finally` clause in a synchronous API:
|
|
1503
|
+
*
|
|
1504
|
+
* // Synchronous API:
|
|
1505
|
+
* try {
|
|
1506
|
+
* doSynchronousWork();
|
|
1507
|
+
* } finally {
|
|
1508
|
+
* cleanUp();
|
|
1509
|
+
* }
|
|
1510
|
+
*
|
|
1511
|
+
* // Asynchronous promise API:
|
|
1512
|
+
* promise.finally(doAsynchronousWork(), cleanUp);
|
|
1513
|
+
*
|
|
1514
|
+
* __Note:__ similar to the `finally` clause, if the registered callback returns
|
|
1515
|
+
* a rejected promise or throws an error, that error will silently replace the
|
|
1516
|
+
* rejection (if any) from the initial promise:
|
|
1517
|
+
*
|
|
1518
|
+
* try {
|
|
1519
|
+
* throw Error('one');
|
|
1520
|
+
* } finally {
|
|
1521
|
+
* throw Error('two'); // Hides Error: one
|
|
1522
|
+
* }
|
|
1523
|
+
*
|
|
1524
|
+
* let p = promise.rejected(Error('one'));
|
|
1525
|
+
* promise.finally(p, function() {
|
|
1526
|
+
* throw Error('two'); // Hides Error: one
|
|
1527
|
+
* });
|
|
1528
|
+
*
|
|
1529
|
+
* @param {PROMISE_TYPE} promise The thenable, promise-like object with which
|
|
1530
|
+
* to register the callback.
|
|
1531
|
+
* @param {function(): *} callback The function to call when the promise is
|
|
1532
|
+
* resolved.
|
|
1533
|
+
* @return {!PROMISE_TYPE} A new promise that is chained to the callback. This
|
|
1534
|
+
* promise will inherit the value of the original input if the callback
|
|
1535
|
+
* does not throw or return a rejected promise.
|
|
1536
|
+
* @template PROMISE_TYPE
|
|
1537
|
+
* @deprecated
|
|
1538
|
+
*/
|
|
1539
|
+
function thenFinally(promise, callback) {
|
|
1540
|
+
if (!isPromise(promise)) {
|
|
1541
|
+
throw TypeError('first argument must be a promise-like object');
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
if (typeof callback !== 'function') {
|
|
1545
|
+
throw TypeError('second argument must be a function');
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
let error;
|
|
1549
|
+
let mustThrow = false;
|
|
1550
|
+
return promise
|
|
1551
|
+
.then(() => callback(), (e) => {
|
|
1552
|
+
error = e;
|
|
1553
|
+
mustThrow = true;
|
|
1554
|
+
return callback();
|
|
1555
|
+
})
|
|
1556
|
+
.then(() => {
|
|
1557
|
+
if (mustThrow) {
|
|
1558
|
+
throw error;
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1439
1562
|
|
|
1440
1563
|
|
|
1441
1564
|
/**
|
|
@@ -1446,11 +1569,8 @@ promise.Thenable.addImplementation(promise.Deferred);
|
|
|
1446
1569
|
*/
|
|
1447
1570
|
function isError(value) {
|
|
1448
1571
|
return value instanceof Error ||
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
// A special test for goog.testing.JsUnitException.
|
|
1452
|
-
value.isJsUnitException);
|
|
1453
|
-
|
|
1572
|
+
(!!value && typeof value === 'object'
|
|
1573
|
+
&& typeof value.message === 'string');
|
|
1454
1574
|
}
|
|
1455
1575
|
|
|
1456
1576
|
|
|
@@ -1458,97 +1578,101 @@ function isError(value) {
|
|
|
1458
1578
|
* Determines whether a {@code value} should be treated as a promise.
|
|
1459
1579
|
* Any object whose "then" property is a function will be considered a promise.
|
|
1460
1580
|
*
|
|
1461
|
-
* @param {
|
|
1581
|
+
* @param {?} value The value to test.
|
|
1462
1582
|
* @return {boolean} Whether the value is a promise.
|
|
1463
1583
|
*/
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
}
|
|
1584
|
+
function isPromise(value) {
|
|
1585
|
+
try {
|
|
1586
|
+
// Use array notation so the Closure compiler does not obfuscate away our
|
|
1587
|
+
// contract.
|
|
1588
|
+
return value
|
|
1589
|
+
&& (typeof value === 'object' || typeof value === 'function')
|
|
1590
|
+
&& typeof value['then'] === 'function';
|
|
1591
|
+
} catch (ex) {
|
|
1592
|
+
return false;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1472
1595
|
|
|
1473
1596
|
|
|
1474
1597
|
/**
|
|
1475
1598
|
* Creates a promise that will be resolved at a set time in the future.
|
|
1476
1599
|
* @param {number} ms The amount of time, in milliseconds, to wait before
|
|
1477
1600
|
* resolving the promise.
|
|
1478
|
-
* @return {!
|
|
1601
|
+
* @return {!ManagedPromise} The promise.
|
|
1479
1602
|
*/
|
|
1480
|
-
|
|
1603
|
+
function delayed(ms) {
|
|
1481
1604
|
var key;
|
|
1482
|
-
return new
|
|
1605
|
+
return new ManagedPromise(function(fulfill) {
|
|
1483
1606
|
key = setTimeout(function() {
|
|
1484
1607
|
key = null;
|
|
1485
1608
|
fulfill();
|
|
1486
1609
|
}, ms);
|
|
1487
|
-
}).
|
|
1610
|
+
}).catch(function(e) {
|
|
1488
1611
|
clearTimeout(key);
|
|
1489
1612
|
key = null;
|
|
1490
1613
|
throw e;
|
|
1491
1614
|
});
|
|
1492
|
-
}
|
|
1615
|
+
}
|
|
1493
1616
|
|
|
1494
1617
|
|
|
1495
1618
|
/**
|
|
1496
1619
|
* Creates a new deferred object.
|
|
1497
|
-
* @return {!
|
|
1620
|
+
* @return {!Deferred<T>} The new deferred object.
|
|
1498
1621
|
* @template T
|
|
1499
1622
|
*/
|
|
1500
|
-
|
|
1501
|
-
return new
|
|
1502
|
-
}
|
|
1623
|
+
function defer() {
|
|
1624
|
+
return new Deferred();
|
|
1625
|
+
}
|
|
1503
1626
|
|
|
1504
1627
|
|
|
1505
1628
|
/**
|
|
1506
1629
|
* Creates a promise that has been resolved with the given value.
|
|
1507
1630
|
* @param {T=} opt_value The resolved value.
|
|
1508
|
-
* @return {!
|
|
1631
|
+
* @return {!ManagedPromise<T>} The resolved promise.
|
|
1509
1632
|
* @template T
|
|
1510
1633
|
*/
|
|
1511
|
-
|
|
1512
|
-
if (opt_value instanceof
|
|
1634
|
+
function fulfilled(opt_value) {
|
|
1635
|
+
if (opt_value instanceof ManagedPromise) {
|
|
1513
1636
|
return opt_value;
|
|
1514
1637
|
}
|
|
1515
|
-
return new
|
|
1638
|
+
return new ManagedPromise(function(fulfill) {
|
|
1516
1639
|
fulfill(opt_value);
|
|
1517
1640
|
});
|
|
1518
|
-
}
|
|
1641
|
+
}
|
|
1519
1642
|
|
|
1520
1643
|
|
|
1521
1644
|
/**
|
|
1522
1645
|
* Creates a promise that has been rejected with the given reason.
|
|
1523
1646
|
* @param {*=} opt_reason The rejection reason; may be any value, but is
|
|
1524
1647
|
* usually an Error or a string.
|
|
1525
|
-
* @return {!
|
|
1648
|
+
* @return {!ManagedPromise<T>} The rejected promise.
|
|
1526
1649
|
* @template T
|
|
1527
1650
|
*/
|
|
1528
|
-
|
|
1529
|
-
if (opt_reason instanceof
|
|
1651
|
+
function rejected(opt_reason) {
|
|
1652
|
+
if (opt_reason instanceof ManagedPromise) {
|
|
1530
1653
|
return opt_reason;
|
|
1531
1654
|
}
|
|
1532
|
-
return new
|
|
1655
|
+
return new ManagedPromise(function(_, reject) {
|
|
1533
1656
|
reject(opt_reason);
|
|
1534
1657
|
});
|
|
1535
|
-
}
|
|
1658
|
+
}
|
|
1536
1659
|
|
|
1537
1660
|
|
|
1538
1661
|
/**
|
|
1539
1662
|
* Wraps a function that expects a node-style callback as its final
|
|
1540
1663
|
* argument. This callback expects two arguments: an error value (which will be
|
|
1541
1664
|
* null if the call succeeded), and the success value as the second argument.
|
|
1542
|
-
* The callback will the resolve or reject the returned promise, based on its
|
|
1665
|
+
* The callback will the resolve or reject the returned promise, based on its
|
|
1666
|
+
* arguments.
|
|
1543
1667
|
* @param {!Function} fn The function to wrap.
|
|
1544
1668
|
* @param {...?} var_args The arguments to apply to the function, excluding the
|
|
1545
1669
|
* final callback.
|
|
1546
|
-
* @return {!
|
|
1670
|
+
* @return {!ManagedPromise} A promise that will be resolved with the
|
|
1547
1671
|
* result of the provided function's callback.
|
|
1548
1672
|
*/
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
return new
|
|
1673
|
+
function checkedNodeCall(fn, var_args) {
|
|
1674
|
+
let args = Array.prototype.slice.call(arguments, 1);
|
|
1675
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1552
1676
|
try {
|
|
1553
1677
|
args.push(function(error, value) {
|
|
1554
1678
|
error ? reject(error) : fulfill(value);
|
|
@@ -1558,7 +1682,7 @@ promise.checkedNodeCall = function(fn, var_args) {
|
|
|
1558
1682
|
reject(ex);
|
|
1559
1683
|
}
|
|
1560
1684
|
});
|
|
1561
|
-
}
|
|
1685
|
+
}
|
|
1562
1686
|
|
|
1563
1687
|
|
|
1564
1688
|
/**
|
|
@@ -1570,43 +1694,37 @@ promise.checkedNodeCall = function(fn, var_args) {
|
|
|
1570
1694
|
* resolved successfully.
|
|
1571
1695
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1572
1696
|
* rejected.
|
|
1573
|
-
* @return {!
|
|
1697
|
+
* @return {!ManagedPromise} A new promise.
|
|
1574
1698
|
*/
|
|
1575
|
-
|
|
1576
|
-
if (
|
|
1699
|
+
function when(value, opt_callback, opt_errback) {
|
|
1700
|
+
if (Thenable.isImplementation(value)) {
|
|
1577
1701
|
return value.then(opt_callback, opt_errback);
|
|
1578
1702
|
}
|
|
1579
1703
|
|
|
1580
|
-
return new
|
|
1581
|
-
|
|
1704
|
+
return new ManagedPromise(function(fulfill) {
|
|
1705
|
+
fulfill(value);
|
|
1582
1706
|
}).then(opt_callback, opt_errback);
|
|
1583
|
-
}
|
|
1707
|
+
}
|
|
1584
1708
|
|
|
1585
1709
|
|
|
1586
1710
|
/**
|
|
1587
|
-
* Invokes the appropriate callback function as soon as a promised
|
|
1588
|
-
*
|
|
1589
|
-
*
|
|
1711
|
+
* Invokes the appropriate callback function as soon as a promised `value` is
|
|
1712
|
+
* resolved. This function is similar to `when()`, except it does not return
|
|
1713
|
+
* a new promise.
|
|
1590
1714
|
* @param {*} value The value to observe.
|
|
1591
1715
|
* @param {Function} callback The function to call when the value is
|
|
1592
1716
|
* resolved successfully.
|
|
1593
1717
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1594
1718
|
* rejected.
|
|
1595
1719
|
*/
|
|
1596
|
-
|
|
1597
|
-
if (
|
|
1720
|
+
function asap(value, callback, opt_errback) {
|
|
1721
|
+
if (isPromise(value)) {
|
|
1598
1722
|
value.then(callback, opt_errback);
|
|
1599
1723
|
|
|
1600
|
-
// Maybe a Dojo-like deferred object?
|
|
1601
|
-
} else if (!!value && goog.isObject(value) &&
|
|
1602
|
-
goog.isFunction(value.addCallbacks)) {
|
|
1603
|
-
value.addCallbacks(callback, opt_errback);
|
|
1604
|
-
|
|
1605
|
-
// A raw value, return a resolved promise.
|
|
1606
1724
|
} else if (callback) {
|
|
1607
1725
|
callback(value);
|
|
1608
1726
|
}
|
|
1609
|
-
}
|
|
1727
|
+
}
|
|
1610
1728
|
|
|
1611
1729
|
|
|
1612
1730
|
/**
|
|
@@ -1615,16 +1733,16 @@ promise.asap = function(value, callback, opt_errback) {
|
|
|
1615
1733
|
* input array's promises are rejected, the returned promise will be rejected
|
|
1616
1734
|
* with the same reason.
|
|
1617
1735
|
*
|
|
1618
|
-
* @param {!Array<(T|!
|
|
1736
|
+
* @param {!Array<(T|!ManagedPromise<T>)>} arr An array of
|
|
1619
1737
|
* promises to wait on.
|
|
1620
|
-
* @return {!
|
|
1738
|
+
* @return {!ManagedPromise<!Array<T>>} A promise that is
|
|
1621
1739
|
* fulfilled with an array containing the fulfilled values of the
|
|
1622
1740
|
* input array, or rejected with the same reason as the first
|
|
1623
1741
|
* rejected value.
|
|
1624
1742
|
* @template T
|
|
1625
1743
|
*/
|
|
1626
|
-
|
|
1627
|
-
return new
|
|
1744
|
+
function all(arr) {
|
|
1745
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1628
1746
|
var n = arr.length;
|
|
1629
1747
|
var values = [];
|
|
1630
1748
|
|
|
@@ -1642,11 +1760,17 @@ promise.all = function(arr) {
|
|
|
1642
1760
|
}
|
|
1643
1761
|
};
|
|
1644
1762
|
|
|
1763
|
+
function processPromise(index) {
|
|
1764
|
+
asap(arr[index], function(value) {
|
|
1765
|
+
onFulfilled(index, value);
|
|
1766
|
+
}, reject);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1645
1769
|
for (var i = 0; i < n; ++i) {
|
|
1646
|
-
|
|
1770
|
+
processPromise(i);
|
|
1647
1771
|
}
|
|
1648
1772
|
});
|
|
1649
|
-
}
|
|
1773
|
+
}
|
|
1650
1774
|
|
|
1651
1775
|
|
|
1652
1776
|
/**
|
|
@@ -1662,7 +1786,7 @@ promise.all = function(arr) {
|
|
|
1662
1786
|
* Only the first failure will be reported; all subsequent errors will be
|
|
1663
1787
|
* silently ignored.
|
|
1664
1788
|
*
|
|
1665
|
-
* @param {!(Array<TYPE>|
|
|
1789
|
+
* @param {!(Array<TYPE>|ManagedPromise<!Array<TYPE>>)} arr The
|
|
1666
1790
|
* array to iterator over, or a promise that will resolve to said array.
|
|
1667
1791
|
* @param {function(this: SELF, TYPE, number, !Array<TYPE>): ?} fn The
|
|
1668
1792
|
* function to call for each element in the array. This function should
|
|
@@ -1671,11 +1795,13 @@ promise.all = function(arr) {
|
|
|
1671
1795
|
* {@code fn}.
|
|
1672
1796
|
* @template TYPE, SELF
|
|
1673
1797
|
*/
|
|
1674
|
-
|
|
1675
|
-
return
|
|
1676
|
-
|
|
1798
|
+
function map(arr, fn, opt_self) {
|
|
1799
|
+
return fulfilled(arr).then(function(v) {
|
|
1800
|
+
if (!Array.isArray(v)) {
|
|
1801
|
+
throw TypeError('not an array');
|
|
1802
|
+
}
|
|
1677
1803
|
var arr = /** @type {!Array} */(v);
|
|
1678
|
-
return new
|
|
1804
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1679
1805
|
var n = arr.length;
|
|
1680
1806
|
var values = new Array(n);
|
|
1681
1807
|
(function processNext(i) {
|
|
@@ -1689,7 +1815,7 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1689
1815
|
return;
|
|
1690
1816
|
}
|
|
1691
1817
|
try {
|
|
1692
|
-
|
|
1818
|
+
asap(
|
|
1693
1819
|
fn.call(opt_self, arr[i], i, /** @type {!Array} */(arr)),
|
|
1694
1820
|
function(value) {
|
|
1695
1821
|
values[i] = value;
|
|
@@ -1702,7 +1828,7 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1702
1828
|
})(0);
|
|
1703
1829
|
});
|
|
1704
1830
|
});
|
|
1705
|
-
}
|
|
1831
|
+
}
|
|
1706
1832
|
|
|
1707
1833
|
|
|
1708
1834
|
/**
|
|
@@ -1718,20 +1844,22 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1718
1844
|
* first failure will be reported; all subsequent errors will be silently
|
|
1719
1845
|
* ignored.
|
|
1720
1846
|
*
|
|
1721
|
-
* @param {!(Array<TYPE>|
|
|
1847
|
+
* @param {!(Array<TYPE>|ManagedPromise<!Array<TYPE>>)} arr The
|
|
1722
1848
|
* array to iterator over, or a promise that will resolve to said array.
|
|
1723
1849
|
* @param {function(this: SELF, TYPE, number, !Array<TYPE>): (
|
|
1724
|
-
* boolean|
|
|
1850
|
+
* boolean|ManagedPromise<boolean>)} fn The function
|
|
1725
1851
|
* to call for each element in the array.
|
|
1726
1852
|
* @param {SELF=} opt_self The object to be used as the value of 'this' within
|
|
1727
1853
|
* {@code fn}.
|
|
1728
1854
|
* @template TYPE, SELF
|
|
1729
1855
|
*/
|
|
1730
|
-
|
|
1731
|
-
return
|
|
1732
|
-
|
|
1856
|
+
function filter(arr, fn, opt_self) {
|
|
1857
|
+
return fulfilled(arr).then(function(v) {
|
|
1858
|
+
if (!Array.isArray(v)) {
|
|
1859
|
+
throw TypeError('not an array');
|
|
1860
|
+
}
|
|
1733
1861
|
var arr = /** @type {!Array} */(v);
|
|
1734
|
-
return new
|
|
1862
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1735
1863
|
var n = arr.length;
|
|
1736
1864
|
var values = [];
|
|
1737
1865
|
var valuesLength = 0;
|
|
@@ -1748,7 +1876,7 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1748
1876
|
try {
|
|
1749
1877
|
var value = arr[i];
|
|
1750
1878
|
var include = fn.call(opt_self, value, i, /** @type {!Array} */(arr));
|
|
1751
|
-
|
|
1879
|
+
asap(include, function(include) {
|
|
1752
1880
|
if (include) {
|
|
1753
1881
|
values[valuesLength++] = value;
|
|
1754
1882
|
}
|
|
@@ -1760,7 +1888,7 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1760
1888
|
})(0);
|
|
1761
1889
|
});
|
|
1762
1890
|
});
|
|
1763
|
-
}
|
|
1891
|
+
}
|
|
1764
1892
|
|
|
1765
1893
|
|
|
1766
1894
|
/**
|
|
@@ -1779,90 +1907,91 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1779
1907
|
* promise.fullyResolved(value); // Stack overflow.
|
|
1780
1908
|
*
|
|
1781
1909
|
* @param {*} value The value to fully resolve.
|
|
1782
|
-
* @return {!
|
|
1910
|
+
* @return {!ManagedPromise} A promise for a fully resolved version
|
|
1783
1911
|
* of the input value.
|
|
1784
1912
|
*/
|
|
1785
|
-
|
|
1786
|
-
if (
|
|
1787
|
-
return
|
|
1913
|
+
function fullyResolved(value) {
|
|
1914
|
+
if (isPromise(value)) {
|
|
1915
|
+
return when(value, fullyResolveValue);
|
|
1788
1916
|
}
|
|
1789
1917
|
return fullyResolveValue(value);
|
|
1790
|
-
}
|
|
1918
|
+
}
|
|
1791
1919
|
|
|
1792
1920
|
|
|
1793
1921
|
/**
|
|
1794
1922
|
* @param {*} value The value to fully resolve. If a promise, assumed to
|
|
1795
1923
|
* already be resolved.
|
|
1796
|
-
* @return {!
|
|
1924
|
+
* @return {!ManagedPromise} A promise for a fully resolved version
|
|
1797
1925
|
* of the input value.
|
|
1798
1926
|
*/
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
case 'object':
|
|
1805
|
-
if (promise.isPromise(value)) {
|
|
1806
|
-
// We get here when the original input value is a promise that
|
|
1807
|
-
// resolves to itself. When the user provides us with such a promise,
|
|
1808
|
-
// trust that it counts as a "fully resolved" value and return it.
|
|
1809
|
-
// Of course, since it's already a promise, we can just return it
|
|
1810
|
-
// to the user instead of wrapping it in another promise.
|
|
1811
|
-
return /** @type {!promise.Promise} */ (value);
|
|
1812
|
-
}
|
|
1927
|
+
function fullyResolveValue(value) {
|
|
1928
|
+
if (Array.isArray(value)) {
|
|
1929
|
+
return fullyResolveKeys(/** @type {!Array} */ (value));
|
|
1930
|
+
}
|
|
1813
1931
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1932
|
+
if (isPromise(value)) {
|
|
1933
|
+
if (isPromise(value)) {
|
|
1934
|
+
// We get here when the original input value is a promise that
|
|
1935
|
+
// resolves to itself. When the user provides us with such a promise,
|
|
1936
|
+
// trust that it counts as a "fully resolved" value and return it.
|
|
1937
|
+
// Of course, since it's already a promise, we can just return it
|
|
1938
|
+
// to the user instead of wrapping it in another promise.
|
|
1939
|
+
return /** @type {!ManagedPromise} */ (value);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1821
1942
|
|
|
1822
|
-
|
|
1943
|
+
if (value && typeof value === 'object') {
|
|
1944
|
+
return fullyResolveKeys(/** @type {!Object} */ (value));
|
|
1945
|
+
}
|
|
1823
1946
|
|
|
1824
|
-
|
|
1825
|
-
|
|
1947
|
+
if (typeof value === 'function') {
|
|
1948
|
+
return fullyResolveKeys(/** @type {!Object} */ (value));
|
|
1826
1949
|
}
|
|
1950
|
+
|
|
1951
|
+
return fulfilled(value);
|
|
1827
1952
|
}
|
|
1828
1953
|
|
|
1829
1954
|
|
|
1830
1955
|
/**
|
|
1831
1956
|
* @param {!(Array|Object)} obj the object to resolve.
|
|
1832
|
-
* @return {!
|
|
1957
|
+
* @return {!ManagedPromise} A promise that will be resolved with the
|
|
1833
1958
|
* input object once all of its values have been fully resolved.
|
|
1834
1959
|
*/
|
|
1835
|
-
|
|
1836
|
-
var isArray =
|
|
1837
|
-
var numKeys = isArray ? obj.length :
|
|
1960
|
+
function fullyResolveKeys(obj) {
|
|
1961
|
+
var isArray = Array.isArray(obj);
|
|
1962
|
+
var numKeys = isArray ? obj.length : (function() {
|
|
1963
|
+
let n = 0;
|
|
1964
|
+
for (let key in obj) {
|
|
1965
|
+
n += 1;
|
|
1966
|
+
}
|
|
1967
|
+
return n;
|
|
1968
|
+
})();
|
|
1838
1969
|
if (!numKeys) {
|
|
1839
|
-
return
|
|
1970
|
+
return fulfilled(obj);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function forEachProperty(obj, fn) {
|
|
1974
|
+
for (let key in obj) {
|
|
1975
|
+
fn.call(null, obj[key], key, obj);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
function forEachElement(arr, fn) {
|
|
1980
|
+
arr.forEach(fn);
|
|
1840
1981
|
}
|
|
1841
1982
|
|
|
1842
1983
|
var numResolved = 0;
|
|
1843
|
-
return new
|
|
1844
|
-
|
|
1845
|
-
// containing undefined values because "index in array" returns false
|
|
1846
|
-
// when array[index] === undefined (even for x = [undefined, 1]). To get
|
|
1847
|
-
// around this, we need to use our own forEach implementation.
|
|
1848
|
-
// DO NOT REMOVE THIS UNTIL WE NO LONGER SUPPORT IE8. This cannot be
|
|
1849
|
-
// reproduced in IE9 by changing the browser/document modes, it requires an
|
|
1850
|
-
// actual pre-IE9 browser. Yay, IE!
|
|
1851
|
-
var forEachKey = !isArray ? Objects.forEach : function(arr, fn) {
|
|
1852
|
-
var n = arr.length;
|
|
1853
|
-
for (var i = 0; i < n; ++i) {
|
|
1854
|
-
fn.call(null, arr[i], i, arr);
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1984
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1985
|
+
var forEachKey = isArray ? forEachElement: forEachProperty;
|
|
1857
1986
|
|
|
1858
1987
|
forEachKey(obj, function(partialValue, key) {
|
|
1859
|
-
|
|
1860
|
-
|
|
1988
|
+
if (!Array.isArray(partialValue)
|
|
1989
|
+
&& (!partialValue || typeof partialValue !== 'object')) {
|
|
1861
1990
|
maybeResolveValue();
|
|
1862
1991
|
return;
|
|
1863
1992
|
}
|
|
1864
1993
|
|
|
1865
|
-
|
|
1994
|
+
fullyResolved(partialValue).then(
|
|
1866
1995
|
function(resolvedValue) {
|
|
1867
1996
|
obj[key] = resolvedValue;
|
|
1868
1997
|
maybeResolveValue();
|
|
@@ -1881,7 +2010,7 @@ promise.fullyResolved = function(value) {
|
|
|
1881
2010
|
|
|
1882
2011
|
//////////////////////////////////////////////////////////////////////////////
|
|
1883
2012
|
//
|
|
1884
|
-
//
|
|
2013
|
+
// ControlFlow
|
|
1885
2014
|
//
|
|
1886
2015
|
//////////////////////////////////////////////////////////////////////////////
|
|
1887
2016
|
|
|
@@ -1893,37 +2022,33 @@ promise.fullyResolved = function(value) {
|
|
|
1893
2022
|
* the ordered scheduled, starting each task only once those before it have
|
|
1894
2023
|
* completed.
|
|
1895
2024
|
*
|
|
1896
|
-
* Each task scheduled within this flow may return a
|
|
1897
|
-
*
|
|
1898
|
-
*
|
|
1899
|
-
* marking the task as completed.
|
|
2025
|
+
* Each task scheduled within this flow may return a {@link ManagedPromise} to
|
|
2026
|
+
* indicate it is an asynchronous operation. The ControlFlow will wait for such
|
|
2027
|
+
* promises to be resolved before marking the task as completed.
|
|
1900
2028
|
*
|
|
1901
|
-
* Tasks and each callback registered on a {@link
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
*
|
|
2029
|
+
* Tasks and each callback registered on a {@link ManagedPromise} will be run
|
|
2030
|
+
* in their own ControlFlow frame. Any tasks scheduled within a frame will take
|
|
2031
|
+
* priority over previously scheduled tasks. Furthermore, if any of the tasks in
|
|
2032
|
+
* the frame fail, the remainder of the tasks in that frame will be discarded
|
|
2033
|
+
* and the failure will be propagated to the user through the callback/task's
|
|
2034
|
+
* promised result.
|
|
1907
2035
|
*
|
|
1908
2036
|
* Each time a ControlFlow empties its task queue, it will fire an
|
|
1909
|
-
* {@link
|
|
2037
|
+
* {@link ControlFlow.EventType.IDLE IDLE} event. Conversely,
|
|
1910
2038
|
* whenever the flow terminates due to an unhandled error, it will remove all
|
|
1911
2039
|
* remaining tasks in its queue and fire an
|
|
1912
|
-
* {@link
|
|
1913
|
-
*
|
|
1914
|
-
*
|
|
2040
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION UNCAUGHT_EXCEPTION} event.
|
|
2041
|
+
* If there are no listeners registered with the flow, the error will be
|
|
2042
|
+
* rethrown to the global error handler.
|
|
1915
2043
|
*
|
|
1916
|
-
* Refer to the {@link
|
|
2044
|
+
* Refer to the {@link ./promise} module documentation fora detailed
|
|
1917
2045
|
* explanation of how the ControlFlow coordinates task execution.
|
|
1918
2046
|
*
|
|
1919
2047
|
* @final
|
|
1920
2048
|
*/
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
/** @constructor */
|
|
1925
|
-
constructor: function() {
|
|
1926
|
-
promise.ControlFlow.base(this, 'constructor');
|
|
2049
|
+
class ControlFlow extends events.EventEmitter {
|
|
2050
|
+
constructor() {
|
|
2051
|
+
super();
|
|
1927
2052
|
|
|
1928
2053
|
/** @private {boolean} */
|
|
1929
2054
|
this.propagateUnhandledRejections_ = true;
|
|
@@ -1937,7 +2062,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1937
2062
|
/**
|
|
1938
2063
|
* Micro task that controls shutting down the control flow. Upon shut down,
|
|
1939
2064
|
* the flow will emit an
|
|
1940
|
-
* {@link
|
|
2065
|
+
* {@link ControlFlow.EventType.IDLE} event. Idle events
|
|
1941
2066
|
* always follow a brief timeout in order to catch latent errors from the
|
|
1942
2067
|
* last completed task. If this task had a callback registered, but no
|
|
1943
2068
|
* errback, and the task fails, the unhandled failure would not be reported
|
|
@@ -1948,7 +2073,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1948
2073
|
* function() { return promise.rejected('failed'); });
|
|
1949
2074
|
* // Set a callback on the result. This delays reporting the unhandled
|
|
1950
2075
|
* // failure for 1 turn of the event loop.
|
|
1951
|
-
* result.then(
|
|
2076
|
+
* result.then(function() {});
|
|
1952
2077
|
*
|
|
1953
2078
|
* @private {MicroTask}
|
|
1954
2079
|
*/
|
|
@@ -1961,28 +2086,27 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1961
2086
|
* _actually_ something to run. When a control flow is waiting on a task,
|
|
1962
2087
|
* there will be nothing in the JS event loop and the process would
|
|
1963
2088
|
* terminate without this.
|
|
1964
|
-
*
|
|
1965
|
-
* @private {?number}
|
|
2089
|
+
* @private
|
|
1966
2090
|
*/
|
|
1967
2091
|
this.hold_ = null;
|
|
1968
|
-
}
|
|
2092
|
+
}
|
|
1969
2093
|
|
|
1970
2094
|
/**
|
|
1971
2095
|
* Returns a string representation of this control flow, which is its current
|
|
1972
|
-
* {@
|
|
2096
|
+
* {@linkplain #getSchedule() schedule}, sans task stack traces.
|
|
1973
2097
|
* @return {string} The string representation of this contorl flow.
|
|
1974
2098
|
* @override
|
|
1975
2099
|
*/
|
|
1976
|
-
toString
|
|
2100
|
+
toString() {
|
|
1977
2101
|
return this.getSchedule();
|
|
1978
|
-
}
|
|
2102
|
+
}
|
|
1979
2103
|
|
|
1980
2104
|
/**
|
|
1981
2105
|
* Sets whether any unhandled rejections should propagate up through the
|
|
1982
2106
|
* control flow stack and cause rejections within parent tasks. If error
|
|
1983
2107
|
* propagation is disabled, tasks will not be aborted when an unhandled
|
|
1984
2108
|
* promise rejection is detected, but the rejection _will_ trigger an
|
|
1985
|
-
* {@link
|
|
2109
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION}
|
|
1986
2110
|
* event.
|
|
1987
2111
|
*
|
|
1988
2112
|
* The default behavior is to propagate all unhandled rejections. _The use
|
|
@@ -1990,26 +2114,26 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1990
2114
|
*
|
|
1991
2115
|
* @param {boolean} propagate whether to propagate errors.
|
|
1992
2116
|
*/
|
|
1993
|
-
setPropagateUnhandledRejections
|
|
2117
|
+
setPropagateUnhandledRejections(propagate) {
|
|
1994
2118
|
this.propagateUnhandledRejections_ = propagate;
|
|
1995
|
-
}
|
|
2119
|
+
}
|
|
1996
2120
|
|
|
1997
2121
|
/**
|
|
1998
2122
|
* @return {boolean} Whether this flow is currently idle.
|
|
1999
2123
|
*/
|
|
2000
|
-
isIdle
|
|
2124
|
+
isIdle() {
|
|
2001
2125
|
return !this.shutdownTask_ && (!this.taskQueues_ || !this.taskQueues_.size);
|
|
2002
|
-
}
|
|
2126
|
+
}
|
|
2003
2127
|
|
|
2004
2128
|
/**
|
|
2005
2129
|
* Resets this instance, clearing its queue and removing all event listeners.
|
|
2006
2130
|
*/
|
|
2007
|
-
reset
|
|
2131
|
+
reset() {
|
|
2008
2132
|
this.cancelQueues_(new FlowResetError);
|
|
2009
|
-
this.emit(
|
|
2133
|
+
this.emit(ControlFlow.EventType.RESET);
|
|
2010
2134
|
this.removeAllListeners();
|
|
2011
2135
|
this.cancelShutdown_();
|
|
2012
|
-
}
|
|
2136
|
+
}
|
|
2013
2137
|
|
|
2014
2138
|
/**
|
|
2015
2139
|
* Generates an annotated string describing the internal state of this control
|
|
@@ -2020,8 +2144,8 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2020
2144
|
* from when each task was scheduled. Defaults to false.
|
|
2021
2145
|
* @return {string} String representation of this flow's internal state.
|
|
2022
2146
|
*/
|
|
2023
|
-
getSchedule
|
|
2024
|
-
var ret = 'ControlFlow::' +
|
|
2147
|
+
getSchedule(opt_includeStackTraces) {
|
|
2148
|
+
var ret = 'ControlFlow::' + getUid(this);
|
|
2025
2149
|
var activeQueue = this.activeQueue_;
|
|
2026
2150
|
if (!this.taskQueues_ || !this.taskQueues_.size) {
|
|
2027
2151
|
return ret;
|
|
@@ -2066,7 +2190,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2066
2190
|
}
|
|
2067
2191
|
return ret;
|
|
2068
2192
|
}
|
|
2069
|
-
}
|
|
2193
|
+
}
|
|
2070
2194
|
|
|
2071
2195
|
/**
|
|
2072
2196
|
* Returns the currently actively task queue for this flow. If there is no
|
|
@@ -2074,7 +2198,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2074
2198
|
* @return {!TaskQueue} the currently active task queue for this flow.
|
|
2075
2199
|
* @private
|
|
2076
2200
|
*/
|
|
2077
|
-
getActiveQueue_
|
|
2201
|
+
getActiveQueue_() {
|
|
2078
2202
|
if (this.activeQueue_) {
|
|
2079
2203
|
return this.activeQueue_;
|
|
2080
2204
|
}
|
|
@@ -2088,45 +2212,46 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2088
2212
|
.once('end', this.onQueueEnd_, this)
|
|
2089
2213
|
.once('error', this.onQueueError_, this);
|
|
2090
2214
|
|
|
2091
|
-
asyncRun(() => this.activeQueue_ = null
|
|
2215
|
+
asyncRun(() => this.activeQueue_ = null);
|
|
2092
2216
|
this.activeQueue_.start();
|
|
2093
2217
|
return this.activeQueue_;
|
|
2094
|
-
}
|
|
2218
|
+
}
|
|
2095
2219
|
|
|
2096
2220
|
/**
|
|
2097
2221
|
* Schedules a task for execution. If there is nothing currently in the
|
|
2098
2222
|
* queue, the task will be executed in the next turn of the event loop. If
|
|
2099
2223
|
* the task function is a generator, the task will be executed using
|
|
2100
|
-
* {@link
|
|
2224
|
+
* {@link ./promise.consume consume()}.
|
|
2101
2225
|
*
|
|
2102
|
-
* @param {function(): (T|
|
|
2226
|
+
* @param {function(): (T|ManagedPromise<T>)} fn The function to
|
|
2103
2227
|
* call to start the task. If the function returns a
|
|
2104
|
-
* {@link
|
|
2228
|
+
* {@link ManagedPromise}, this instance will wait for it to be
|
|
2105
2229
|
* resolved before starting the next task.
|
|
2106
2230
|
* @param {string=} opt_description A description of the task.
|
|
2107
|
-
* @return {!
|
|
2231
|
+
* @return {!ManagedPromise<T>} A promise that will be resolved
|
|
2108
2232
|
* with the result of the action.
|
|
2109
2233
|
* @template T
|
|
2110
2234
|
*/
|
|
2111
|
-
execute
|
|
2112
|
-
if (
|
|
2113
|
-
|
|
2235
|
+
execute(fn, opt_description) {
|
|
2236
|
+
if (isGenerator(fn)) {
|
|
2237
|
+
let original = fn;
|
|
2238
|
+
fn = () => consume(original);
|
|
2114
2239
|
}
|
|
2115
2240
|
|
|
2116
2241
|
if (!this.hold_) {
|
|
2117
2242
|
var holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
|
|
2118
|
-
this.hold_ = setInterval(
|
|
2243
|
+
this.hold_ = setInterval(function() {}, holdIntervalMs);
|
|
2119
2244
|
}
|
|
2120
2245
|
|
|
2121
2246
|
var task = new Task(
|
|
2122
2247
|
this, fn, opt_description || '<anonymous>',
|
|
2123
|
-
{name: 'Task', top:
|
|
2248
|
+
{name: 'Task', top: ControlFlow.prototype.execute});
|
|
2124
2249
|
|
|
2125
2250
|
var q = this.getActiveQueue_();
|
|
2126
2251
|
q.enqueue(task);
|
|
2127
|
-
this.emit(
|
|
2252
|
+
this.emit(ControlFlow.EventType.SCHEDULE_TASK, task.description);
|
|
2128
2253
|
return task.promise;
|
|
2129
|
-
}
|
|
2254
|
+
}
|
|
2130
2255
|
|
|
2131
2256
|
/**
|
|
2132
2257
|
* Inserts a {@code setTimeout} into the command queue. This is equivalent to
|
|
@@ -2134,14 +2259,14 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2134
2259
|
*
|
|
2135
2260
|
* @param {number} ms The timeout delay, in milliseconds.
|
|
2136
2261
|
* @param {string=} opt_description A description to accompany the timeout.
|
|
2137
|
-
* @return {!
|
|
2262
|
+
* @return {!ManagedPromise} A promise that will be resolved with
|
|
2138
2263
|
* the result of the action.
|
|
2139
2264
|
*/
|
|
2140
|
-
timeout
|
|
2265
|
+
timeout(ms, opt_description) {
|
|
2141
2266
|
return this.execute(function() {
|
|
2142
|
-
return
|
|
2267
|
+
return delayed(ms);
|
|
2143
2268
|
}, opt_description);
|
|
2144
|
-
}
|
|
2269
|
+
}
|
|
2145
2270
|
|
|
2146
2271
|
/**
|
|
2147
2272
|
* Schedules a task that shall wait for a condition to hold. Each condition
|
|
@@ -2151,7 +2276,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2151
2276
|
* Condition functions may schedule sub-tasks with this instance, however,
|
|
2152
2277
|
* their execution time will be factored into whether a wait has timed out.
|
|
2153
2278
|
*
|
|
2154
|
-
* In the event a condition returns a
|
|
2279
|
+
* In the event a condition returns a ManagedPromise, the polling loop will wait for
|
|
2155
2280
|
* it to be resolved before evaluating whether the condition has been
|
|
2156
2281
|
* satisfied. The resolution time for a promise is factored into whether a
|
|
2157
2282
|
* wait has timed out.
|
|
@@ -2166,38 +2291,38 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2166
2291
|
* If this function is invoked with `timeout === 0`, or the timeout is
|
|
2167
2292
|
* omitted, the flow will wait indefinitely for the condition to be satisfied.
|
|
2168
2293
|
*
|
|
2169
|
-
* @param {(!
|
|
2294
|
+
* @param {(!ManagedPromise<T>|function())} condition The condition to poll,
|
|
2170
2295
|
* or a promise to wait on.
|
|
2171
2296
|
* @param {number=} opt_timeout How long to wait, in milliseconds, for the
|
|
2172
2297
|
* condition to hold before timing out. If omitted, the flow will wait
|
|
2173
2298
|
* indefinitely.
|
|
2174
2299
|
* @param {string=} opt_message An optional error message to include if the
|
|
2175
2300
|
* wait times out; defaults to the empty string.
|
|
2176
|
-
* @return {!
|
|
2301
|
+
* @return {!ManagedPromise<T>} A promise that will be fulfilled
|
|
2177
2302
|
* when the condition has been satisified. The promise shall be rejected
|
|
2178
2303
|
* if the wait times out waiting for the condition.
|
|
2179
2304
|
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2180
2305
|
* is not a number >= 0.
|
|
2181
2306
|
* @template T
|
|
2182
2307
|
*/
|
|
2183
|
-
wait
|
|
2308
|
+
wait(condition, opt_timeout, opt_message) {
|
|
2184
2309
|
var timeout = opt_timeout || 0;
|
|
2185
|
-
if (
|
|
2310
|
+
if (typeof timeout !== 'number' || timeout < 0) {
|
|
2186
2311
|
throw TypeError('timeout must be a number >= 0: ' + timeout);
|
|
2187
2312
|
}
|
|
2188
2313
|
|
|
2189
|
-
if (
|
|
2314
|
+
if (isPromise(condition)) {
|
|
2190
2315
|
return this.execute(function() {
|
|
2191
2316
|
if (!timeout) {
|
|
2192
2317
|
return condition;
|
|
2193
2318
|
}
|
|
2194
|
-
return new
|
|
2195
|
-
var start =
|
|
2319
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
2320
|
+
var start = Date.now();
|
|
2196
2321
|
var timer = setTimeout(function() {
|
|
2197
2322
|
timer = null;
|
|
2198
2323
|
reject(Error((opt_message ? opt_message + '\n' : '') +
|
|
2199
2324
|
'Timed out waiting for promise to resolve after ' +
|
|
2200
|
-
(
|
|
2325
|
+
(Date.now() - start) + 'ms'));
|
|
2201
2326
|
}, timeout);
|
|
2202
2327
|
|
|
2203
2328
|
/** @type {Thenable} */(condition).then(
|
|
@@ -2213,25 +2338,26 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2213
2338
|
}, opt_message || '<anonymous wait: promise resolution>');
|
|
2214
2339
|
}
|
|
2215
2340
|
|
|
2216
|
-
if (
|
|
2341
|
+
if (typeof condition !== 'function') {
|
|
2217
2342
|
throw TypeError('Invalid condition; must be a function or promise: ' +
|
|
2218
|
-
|
|
2343
|
+
typeof condition);
|
|
2219
2344
|
}
|
|
2220
2345
|
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
2346
|
+
if (isGenerator(condition)) {
|
|
2347
|
+
let original = condition;
|
|
2348
|
+
condition = () => consume(original);
|
|
2223
2349
|
}
|
|
2224
2350
|
|
|
2225
2351
|
var self = this;
|
|
2226
2352
|
return this.execute(function() {
|
|
2227
|
-
var startTime =
|
|
2228
|
-
return new
|
|
2353
|
+
var startTime = Date.now();
|
|
2354
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
2229
2355
|
pollCondition();
|
|
2230
2356
|
|
|
2231
2357
|
function pollCondition() {
|
|
2232
2358
|
var conditionFn = /** @type {function()} */(condition);
|
|
2233
2359
|
self.execute(conditionFn).then(function(value) {
|
|
2234
|
-
var elapsed =
|
|
2360
|
+
var elapsed = Date.now() - startTime;
|
|
2235
2361
|
if (!!value) {
|
|
2236
2362
|
fulfill(value);
|
|
2237
2363
|
} else if (timeout && elapsed >= timeout) {
|
|
@@ -2247,7 +2373,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2247
2373
|
}
|
|
2248
2374
|
});
|
|
2249
2375
|
}, opt_message || '<anonymous wait>');
|
|
2250
|
-
}
|
|
2376
|
+
}
|
|
2251
2377
|
|
|
2252
2378
|
/**
|
|
2253
2379
|
* Executes a function in the next available turn of the JavaScript event
|
|
@@ -2285,36 +2411,36 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2285
2411
|
* @param {Object=} opt_self The object in whose context to run the function.
|
|
2286
2412
|
* @param {...*} var_args Any arguments to pass to the function.
|
|
2287
2413
|
*/
|
|
2288
|
-
async
|
|
2289
|
-
asyncRun(
|
|
2414
|
+
async(fn, opt_self, var_args) {
|
|
2415
|
+
asyncRun(() => {
|
|
2290
2416
|
// Clear any lingering queues, forces getActiveQueue_ to create a new one.
|
|
2291
2417
|
this.activeQueue_ = null;
|
|
2292
2418
|
var q = this.getActiveQueue_();
|
|
2293
2419
|
try {
|
|
2294
2420
|
q.execute_(fn.bind(opt_self, var_args));
|
|
2295
2421
|
} catch (ex) {
|
|
2296
|
-
var cancellationError =
|
|
2422
|
+
var cancellationError = CancellationError.wrap(ex,
|
|
2297
2423
|
'Function passed to ControlFlow.async() threw');
|
|
2298
2424
|
cancellationError.silent_ = true;
|
|
2299
2425
|
q.abort_(cancellationError);
|
|
2300
2426
|
} finally {
|
|
2301
2427
|
this.activeQueue_ = null;
|
|
2302
2428
|
}
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2305
2431
|
|
|
2306
2432
|
/**
|
|
2307
2433
|
* Event handler for when a task queue is exhausted. This starts the shutdown
|
|
2308
2434
|
* sequence for this instance if there are no remaining task queues: after
|
|
2309
2435
|
* one turn of the event loop, this object will emit the
|
|
2310
|
-
* {@link
|
|
2436
|
+
* {@link ControlFlow.EventType.IDLE IDLE} event to signal
|
|
2311
2437
|
* listeners that it has completed. During this wait, if another task is
|
|
2312
2438
|
* scheduled, the shutdown will be aborted.
|
|
2313
2439
|
*
|
|
2314
2440
|
* @param {!TaskQueue} q the completed task queue.
|
|
2315
2441
|
* @private
|
|
2316
2442
|
*/
|
|
2317
|
-
onQueueEnd_
|
|
2443
|
+
onQueueEnd_(q) {
|
|
2318
2444
|
if (!this.taskQueues_) {
|
|
2319
2445
|
return;
|
|
2320
2446
|
}
|
|
@@ -2324,15 +2450,18 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2324
2450
|
vlog(1, () => this.taskQueues_.size + ' queues remain\n' + this, this);
|
|
2325
2451
|
|
|
2326
2452
|
if (!this.taskQueues_.size) {
|
|
2327
|
-
|
|
2328
|
-
|
|
2453
|
+
if (this.shutdownTask_) {
|
|
2454
|
+
throw Error('Already have a shutdown task??');
|
|
2455
|
+
}
|
|
2456
|
+
vlog(1, () => 'Scheduling shutdown\n' + this);
|
|
2457
|
+
this.shutdownTask_ = new MicroTask(() => this.shutdown_());
|
|
2329
2458
|
}
|
|
2330
|
-
}
|
|
2459
|
+
}
|
|
2331
2460
|
|
|
2332
2461
|
/**
|
|
2333
2462
|
* Event handler for when a task queue terminates with an error. This triggers
|
|
2334
2463
|
* the cancellation of all other task queues and a
|
|
2335
|
-
* {@link
|
|
2464
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
|
|
2336
2465
|
* If there are no error event listeners registered with this instance, the
|
|
2337
2466
|
* error will be rethrown to the global error handler.
|
|
2338
2467
|
*
|
|
@@ -2340,30 +2469,30 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2340
2469
|
* @param {!TaskQueue} q the task queue.
|
|
2341
2470
|
* @private
|
|
2342
2471
|
*/
|
|
2343
|
-
onQueueError_
|
|
2472
|
+
onQueueError_(error, q) {
|
|
2344
2473
|
if (this.taskQueues_) {
|
|
2345
2474
|
this.taskQueues_.delete(q);
|
|
2346
2475
|
}
|
|
2347
|
-
this.cancelQueues_(
|
|
2476
|
+
this.cancelQueues_(CancellationError.wrap(
|
|
2348
2477
|
error, 'There was an uncaught error in the control flow'));
|
|
2349
2478
|
this.cancelShutdown_();
|
|
2350
2479
|
this.cancelHold_();
|
|
2351
2480
|
|
|
2352
2481
|
var listeners = this.listeners(
|
|
2353
|
-
|
|
2354
|
-
if (!listeners.
|
|
2355
|
-
|
|
2482
|
+
ControlFlow.EventType.UNCAUGHT_EXCEPTION);
|
|
2483
|
+
if (!listeners.size) {
|
|
2484
|
+
asyncThrow(/** @type {!Error} */(error));
|
|
2356
2485
|
} else {
|
|
2357
2486
|
this.reportUncaughtException_(error);
|
|
2358
2487
|
}
|
|
2359
|
-
}
|
|
2488
|
+
}
|
|
2360
2489
|
|
|
2361
2490
|
/**
|
|
2362
2491
|
* Cancels all remaining task queues.
|
|
2363
|
-
* @param {!
|
|
2492
|
+
* @param {!CancellationError} reason The cancellation reason.
|
|
2364
2493
|
* @private
|
|
2365
2494
|
*/
|
|
2366
|
-
cancelQueues_
|
|
2495
|
+
cancelQueues_(reason) {
|
|
2367
2496
|
reason.silent_ = true;
|
|
2368
2497
|
if (this.taskQueues_) {
|
|
2369
2498
|
for (var q of this.taskQueues_) {
|
|
@@ -2373,53 +2502,53 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2373
2502
|
this.taskQueues_.clear();
|
|
2374
2503
|
this.taskQueues_ = null;
|
|
2375
2504
|
}
|
|
2376
|
-
}
|
|
2505
|
+
}
|
|
2377
2506
|
|
|
2378
2507
|
/**
|
|
2379
2508
|
* Reports an uncaught exception using a
|
|
2380
|
-
* {@link
|
|
2509
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
|
|
2381
2510
|
*
|
|
2382
2511
|
* @param {*} e the error to report.
|
|
2383
2512
|
* @private
|
|
2384
2513
|
*/
|
|
2385
|
-
reportUncaughtException_
|
|
2386
|
-
this.emit(
|
|
2387
|
-
}
|
|
2514
|
+
reportUncaughtException_(e) {
|
|
2515
|
+
this.emit(ControlFlow.EventType.UNCAUGHT_EXCEPTION, e);
|
|
2516
|
+
}
|
|
2388
2517
|
|
|
2389
2518
|
/** @private */
|
|
2390
|
-
cancelHold_
|
|
2519
|
+
cancelHold_() {
|
|
2391
2520
|
if (this.hold_) {
|
|
2392
2521
|
clearInterval(this.hold_);
|
|
2393
2522
|
this.hold_ = null;
|
|
2394
2523
|
}
|
|
2395
|
-
}
|
|
2524
|
+
}
|
|
2396
2525
|
|
|
2397
2526
|
/** @private */
|
|
2398
|
-
shutdown_
|
|
2527
|
+
shutdown_() {
|
|
2399
2528
|
vlog(1, () => 'Going idle: ' + this);
|
|
2400
2529
|
this.cancelHold_();
|
|
2401
2530
|
this.shutdownTask_ = null;
|
|
2402
|
-
this.emit(
|
|
2403
|
-
}
|
|
2531
|
+
this.emit(ControlFlow.EventType.IDLE);
|
|
2532
|
+
}
|
|
2404
2533
|
|
|
2405
2534
|
/**
|
|
2406
2535
|
* Cancels the shutdown sequence if it is currently scheduled.
|
|
2407
2536
|
* @private
|
|
2408
2537
|
*/
|
|
2409
|
-
cancelShutdown_
|
|
2538
|
+
cancelShutdown_() {
|
|
2410
2539
|
if (this.shutdownTask_) {
|
|
2411
2540
|
this.shutdownTask_.cancel();
|
|
2412
2541
|
this.shutdownTask_ = null;
|
|
2413
2542
|
}
|
|
2414
2543
|
}
|
|
2415
|
-
}
|
|
2544
|
+
}
|
|
2416
2545
|
|
|
2417
2546
|
|
|
2418
2547
|
/**
|
|
2419
|
-
* Events that may be emitted by an {@link
|
|
2548
|
+
* Events that may be emitted by an {@link ControlFlow}.
|
|
2420
2549
|
* @enum {string}
|
|
2421
2550
|
*/
|
|
2422
|
-
|
|
2551
|
+
ControlFlow.EventType = {
|
|
2423
2552
|
|
|
2424
2553
|
/** Emitted when all tasks have been successfully executed. */
|
|
2425
2554
|
IDLE: 'idle',
|
|
@@ -2444,56 +2573,67 @@ promise.ControlFlow.EventType = {
|
|
|
2444
2573
|
* Wraps a function to execute as a cancellable micro task.
|
|
2445
2574
|
* @final
|
|
2446
2575
|
*/
|
|
2447
|
-
|
|
2576
|
+
class MicroTask {
|
|
2448
2577
|
/**
|
|
2449
|
-
* @param {function(
|
|
2450
|
-
* @param {THIS=} opt_scope The scope to run the function in.
|
|
2451
|
-
* @template THIS
|
|
2578
|
+
* @param {function()} fn The function to run as a micro task.
|
|
2452
2579
|
*/
|
|
2453
|
-
constructor
|
|
2580
|
+
constructor(fn) {
|
|
2454
2581
|
/** @private {boolean} */
|
|
2455
2582
|
this.cancelled_ = false;
|
|
2456
|
-
asyncRun(
|
|
2583
|
+
asyncRun(() => {
|
|
2457
2584
|
if (!this.cancelled_) {
|
|
2458
|
-
fn
|
|
2585
|
+
fn();
|
|
2459
2586
|
}
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
/**
|
|
2591
|
+
* Runs the given function after a micro-task yield.
|
|
2592
|
+
* @param {function()} fn The function to run.
|
|
2593
|
+
*/
|
|
2594
|
+
static run(fn) {
|
|
2595
|
+
NativePromise.resolve().then(function() {
|
|
2596
|
+
try {
|
|
2597
|
+
fn();
|
|
2598
|
+
} catch (ignored) {
|
|
2599
|
+
// Do nothing.
|
|
2600
|
+
}
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2462
2603
|
|
|
2463
2604
|
/**
|
|
2464
2605
|
* Cancels the execution of this task. Note: this will not prevent the task
|
|
2465
2606
|
* timer from firing, just the invocation of the wrapped function.
|
|
2466
2607
|
*/
|
|
2467
|
-
cancel
|
|
2608
|
+
cancel() {
|
|
2468
2609
|
this.cancelled_ = true;
|
|
2469
2610
|
}
|
|
2470
|
-
}
|
|
2611
|
+
}
|
|
2471
2612
|
|
|
2472
2613
|
|
|
2473
2614
|
/**
|
|
2474
|
-
* A task to be executed by a {@link
|
|
2615
|
+
* A task to be executed by a {@link ControlFlow}.
|
|
2475
2616
|
*
|
|
2617
|
+
* @template T
|
|
2476
2618
|
* @final
|
|
2477
2619
|
*/
|
|
2478
|
-
|
|
2620
|
+
class Task extends Deferred {
|
|
2479
2621
|
/**
|
|
2480
|
-
* @param {!
|
|
2622
|
+
* @param {!ControlFlow} flow The flow this instances belongs
|
|
2481
2623
|
* to.
|
|
2482
|
-
* @param {function(): (T|!
|
|
2624
|
+
* @param {function(): (T|!ManagedPromise<T>)} fn The function to
|
|
2483
2625
|
* call when the task executes. If it returns a
|
|
2484
|
-
* {@link
|
|
2626
|
+
* {@link ManagedPromise}, the flow will wait for it to be
|
|
2485
2627
|
* resolved before starting the next task.
|
|
2486
2628
|
* @param {string} description A description of the task for debugging.
|
|
2487
2629
|
* @param {{name: string, top: !Function}=} opt_stackOptions Options to use
|
|
2488
2630
|
* when capturing the stacktrace for when this task was created.
|
|
2489
|
-
* @constructor
|
|
2490
|
-
* @extends {promise.Deferred<T>}
|
|
2491
|
-
* @template T
|
|
2492
2631
|
*/
|
|
2493
|
-
constructor
|
|
2494
|
-
|
|
2632
|
+
constructor(flow, fn, description, opt_stackOptions) {
|
|
2633
|
+
super(flow);
|
|
2634
|
+
getUid(this);
|
|
2495
2635
|
|
|
2496
|
-
/** @type {function(): (T|!
|
|
2636
|
+
/** @type {function(): (T|!ManagedPromise<T>)} */
|
|
2497
2637
|
this.execute = fn;
|
|
2498
2638
|
|
|
2499
2639
|
/** @type {string} */
|
|
@@ -2519,20 +2659,20 @@ var Task = goog.defineClass(promise.Deferred, {
|
|
|
2519
2659
|
this.blocked = false;
|
|
2520
2660
|
|
|
2521
2661
|
if (opt_stackOptions) {
|
|
2522
|
-
this.promise.stack_ =
|
|
2662
|
+
this.promise.stack_ = captureStackTrace(
|
|
2523
2663
|
opt_stackOptions.name, this.description, opt_stackOptions.top);
|
|
2524
2664
|
}
|
|
2525
|
-
}
|
|
2665
|
+
}
|
|
2526
2666
|
|
|
2527
2667
|
/** @override */
|
|
2528
|
-
toString
|
|
2529
|
-
return 'Task::' +
|
|
2668
|
+
toString() {
|
|
2669
|
+
return 'Task::' + getUid(this) + '<' + this.description + '>';
|
|
2530
2670
|
}
|
|
2531
|
-
}
|
|
2671
|
+
}
|
|
2532
2672
|
|
|
2533
2673
|
|
|
2534
2674
|
/** @enum {string} */
|
|
2535
|
-
|
|
2675
|
+
const TaskQueueState = {
|
|
2536
2676
|
NEW: 'new',
|
|
2537
2677
|
STARTED: 'started',
|
|
2538
2678
|
FINISHED: 'finished'
|
|
@@ -2542,16 +2682,15 @@ var TaskQueueState = {
|
|
|
2542
2682
|
/**
|
|
2543
2683
|
* @final
|
|
2544
2684
|
*/
|
|
2545
|
-
|
|
2546
|
-
/** @param {!
|
|
2547
|
-
constructor
|
|
2548
|
-
|
|
2549
|
-
goog.getUid(this);
|
|
2685
|
+
class TaskQueue extends events.EventEmitter {
|
|
2686
|
+
/** @param {!ControlFlow} flow . */
|
|
2687
|
+
constructor(flow) {
|
|
2688
|
+
super();
|
|
2550
2689
|
|
|
2551
2690
|
/** @private {string} */
|
|
2552
|
-
this.name_ = 'TaskQueue::' +
|
|
2691
|
+
this.name_ = 'TaskQueue::' + getUid(this);
|
|
2553
2692
|
|
|
2554
|
-
/** @private {!
|
|
2693
|
+
/** @private {!ControlFlow} */
|
|
2555
2694
|
this.flow_ = flow;
|
|
2556
2695
|
|
|
2557
2696
|
/** @private {!Array<!Task>} */
|
|
@@ -2566,41 +2705,41 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2566
2705
|
/** @private {TaskQueueState} */
|
|
2567
2706
|
this.state_ = TaskQueueState.NEW;
|
|
2568
2707
|
|
|
2569
|
-
/** @private {!Set<!
|
|
2708
|
+
/** @private {!Set<!ManagedPromise>} */
|
|
2570
2709
|
this.unhandledRejections_ = new Set();
|
|
2571
|
-
}
|
|
2710
|
+
}
|
|
2572
2711
|
|
|
2573
2712
|
/** @override */
|
|
2574
|
-
toString
|
|
2575
|
-
return 'TaskQueue::' +
|
|
2576
|
-
}
|
|
2713
|
+
toString() {
|
|
2714
|
+
return 'TaskQueue::' + getUid(this);
|
|
2715
|
+
}
|
|
2577
2716
|
|
|
2578
2717
|
/**
|
|
2579
|
-
* @param {!
|
|
2718
|
+
* @param {!ManagedPromise} promise .
|
|
2580
2719
|
*/
|
|
2581
|
-
addUnhandledRejection
|
|
2720
|
+
addUnhandledRejection(promise) {
|
|
2582
2721
|
// TODO: node 4.0.0+
|
|
2583
2722
|
vlog(2, () => this + ' registering unhandled rejection: ' + promise, this);
|
|
2584
2723
|
this.unhandledRejections_.add(promise);
|
|
2585
|
-
}
|
|
2724
|
+
}
|
|
2586
2725
|
|
|
2587
2726
|
/**
|
|
2588
|
-
* @param {!
|
|
2727
|
+
* @param {!ManagedPromise} promise .
|
|
2589
2728
|
*/
|
|
2590
|
-
clearUnhandledRejection
|
|
2729
|
+
clearUnhandledRejection(promise) {
|
|
2591
2730
|
var deleted = this.unhandledRejections_.delete(promise);
|
|
2592
2731
|
if (deleted) {
|
|
2593
2732
|
// TODO: node 4.0.0+
|
|
2594
2733
|
vlog(2, () => this + ' clearing unhandled rejection: ' + promise, this);
|
|
2595
2734
|
}
|
|
2596
|
-
}
|
|
2735
|
+
}
|
|
2597
2736
|
|
|
2598
2737
|
/**
|
|
2599
2738
|
* Enqueues a new task for execution.
|
|
2600
2739
|
* @param {!Task} task The task to enqueue.
|
|
2601
2740
|
* @throws {Error} If this instance has already started execution.
|
|
2602
2741
|
*/
|
|
2603
|
-
enqueue
|
|
2742
|
+
enqueue(task) {
|
|
2604
2743
|
if (this.state_ !== TaskQueueState.NEW) {
|
|
2605
2744
|
throw Error('TaskQueue has started: ' + this);
|
|
2606
2745
|
}
|
|
@@ -2616,16 +2755,16 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2616
2755
|
|
|
2617
2756
|
vlog(1, () => this + '.enqueue(' + task + ')', this);
|
|
2618
2757
|
vlog(2, () => this.flow_.toString(), this);
|
|
2619
|
-
}
|
|
2758
|
+
}
|
|
2620
2759
|
|
|
2621
2760
|
/**
|
|
2622
2761
|
* Schedules the callbacks registered on the given promise in this queue.
|
|
2623
2762
|
*
|
|
2624
|
-
* @param {!
|
|
2763
|
+
* @param {!ManagedPromise} promise the promise whose callbacks should be
|
|
2625
2764
|
* registered as interrupts in this task queue.
|
|
2626
2765
|
* @throws {Error} if this queue has already finished.
|
|
2627
2766
|
*/
|
|
2628
|
-
scheduleCallbacks
|
|
2767
|
+
scheduleCallbacks(promise) {
|
|
2629
2768
|
if (this.state_ === TaskQueueState.FINISHED) {
|
|
2630
2769
|
throw new Error('cannot interrupt a finished q(' + this + ')');
|
|
2631
2770
|
}
|
|
@@ -2633,7 +2772,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2633
2772
|
if (this.pending_ && this.pending_.task.promise === promise) {
|
|
2634
2773
|
this.pending_.task.promise.queue_ = null;
|
|
2635
2774
|
this.pending_ = null;
|
|
2636
|
-
asyncRun(this.executeNext_
|
|
2775
|
+
asyncRun(() => this.executeNext_());
|
|
2637
2776
|
}
|
|
2638
2777
|
|
|
2639
2778
|
if (!promise.callbacks_) {
|
|
@@ -2663,7 +2802,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2663
2802
|
}, this);
|
|
2664
2803
|
promise.callbacks_ = null;
|
|
2665
2804
|
vlog(2, () => this + ' interrupted\n' + this.flow_, this);
|
|
2666
|
-
}
|
|
2805
|
+
}
|
|
2667
2806
|
|
|
2668
2807
|
/**
|
|
2669
2808
|
* Starts executing tasks in this queue. Once called, no further tasks may
|
|
@@ -2671,15 +2810,15 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2671
2810
|
*
|
|
2672
2811
|
* @throws {Error} if this queue has already been started.
|
|
2673
2812
|
*/
|
|
2674
|
-
start
|
|
2813
|
+
start() {
|
|
2675
2814
|
if (this.state_ !== TaskQueueState.NEW) {
|
|
2676
2815
|
throw new Error('TaskQueue has already started');
|
|
2677
2816
|
}
|
|
2678
2817
|
// Always asynchronously execute next, even if there doesn't look like
|
|
2679
2818
|
// there is anything in the queue. This will catch pending unhandled
|
|
2680
2819
|
// rejections that were registered before start was called.
|
|
2681
|
-
asyncRun(this.executeNext_
|
|
2682
|
-
}
|
|
2820
|
+
asyncRun(() => this.executeNext_());
|
|
2821
|
+
}
|
|
2683
2822
|
|
|
2684
2823
|
/**
|
|
2685
2824
|
* Aborts this task queue. If there are any scheduled tasks, they are silently
|
|
@@ -2690,7 +2829,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2690
2829
|
* @param {*} error The abortion reason.
|
|
2691
2830
|
* @private
|
|
2692
2831
|
*/
|
|
2693
|
-
abort_
|
|
2832
|
+
abort_(error) {
|
|
2694
2833
|
var cancellation;
|
|
2695
2834
|
|
|
2696
2835
|
if (error instanceof FlowResetError) {
|
|
@@ -2711,23 +2850,22 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2711
2850
|
|
|
2712
2851
|
if (this.pending_) {
|
|
2713
2852
|
vlog(2, () => this + '.abort(); cancelling pending task', this);
|
|
2714
|
-
this.pending_.task.cancel(
|
|
2715
|
-
/** @type {!webdriver.promise.CancellationError} */(error));
|
|
2853
|
+
this.pending_.task.cancel(/** @type {!CancellationError} */(error));
|
|
2716
2854
|
|
|
2717
2855
|
} else {
|
|
2718
2856
|
vlog(2, () => this + '.abort(); emitting error event', this);
|
|
2719
2857
|
this.emit('error', error, this);
|
|
2720
2858
|
}
|
|
2721
|
-
}
|
|
2859
|
+
}
|
|
2722
2860
|
|
|
2723
2861
|
/** @private */
|
|
2724
|
-
executeNext_
|
|
2862
|
+
executeNext_() {
|
|
2725
2863
|
if (this.state_ === TaskQueueState.FINISHED) {
|
|
2726
2864
|
return;
|
|
2727
2865
|
}
|
|
2728
2866
|
this.state_ = TaskQueueState.STARTED;
|
|
2729
2867
|
|
|
2730
|
-
if (this.pending_
|
|
2868
|
+
if (this.pending_ !== null || this.processUnhandledRejections_()) {
|
|
2731
2869
|
return;
|
|
2732
2870
|
}
|
|
2733
2871
|
|
|
@@ -2760,8 +2898,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2760
2898
|
} catch (ex) {
|
|
2761
2899
|
subQ.abort_(ex);
|
|
2762
2900
|
}
|
|
2763
|
-
}
|
|
2764
|
-
|
|
2901
|
+
}
|
|
2765
2902
|
|
|
2766
2903
|
/**
|
|
2767
2904
|
* @param {!Function} fn .
|
|
@@ -2769,7 +2906,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2769
2906
|
* @template T
|
|
2770
2907
|
* @private
|
|
2771
2908
|
*/
|
|
2772
|
-
execute_
|
|
2909
|
+
execute_(fn) {
|
|
2773
2910
|
try {
|
|
2774
2911
|
activeFlows.push(this.flow_);
|
|
2775
2912
|
this.flow_.activeQueue_ = this;
|
|
@@ -2778,17 +2915,17 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2778
2915
|
this.flow_.activeQueue_ = null;
|
|
2779
2916
|
activeFlows.pop();
|
|
2780
2917
|
}
|
|
2781
|
-
}
|
|
2918
|
+
}
|
|
2782
2919
|
|
|
2783
2920
|
/**
|
|
2784
2921
|
* Process any unhandled rejections registered with this task queue. If there
|
|
2785
2922
|
* is a rejection, this queue will be aborted with the rejection error. If
|
|
2786
2923
|
* there are multiple rejections registered, this queue will be aborted with
|
|
2787
|
-
* a {@link
|
|
2924
|
+
* a {@link MultipleUnhandledRejectionError}.
|
|
2788
2925
|
* @return {boolean} whether there was an unhandled rejection.
|
|
2789
2926
|
* @private
|
|
2790
2927
|
*/
|
|
2791
|
-
processUnhandledRejections_
|
|
2928
|
+
processUnhandledRejections_() {
|
|
2792
2929
|
if (!this.unhandledRejections_.size) {
|
|
2793
2930
|
return false;
|
|
2794
2931
|
}
|
|
@@ -2801,7 +2938,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2801
2938
|
|
|
2802
2939
|
var errorToReport = errors.size === 1
|
|
2803
2940
|
? errors.values().next().value
|
|
2804
|
-
: new
|
|
2941
|
+
: new MultipleUnhandledRejectionError(errors);
|
|
2805
2942
|
|
|
2806
2943
|
vlog(1, () => this + ' aborting due to unhandled rejections', this);
|
|
2807
2944
|
if (this.flow_.propagateUnhandledRejections_) {
|
|
@@ -2812,13 +2949,13 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2812
2949
|
this.flow_.reportUncaughtException_(errorToReport);
|
|
2813
2950
|
return false;
|
|
2814
2951
|
}
|
|
2815
|
-
}
|
|
2952
|
+
}
|
|
2816
2953
|
|
|
2817
2954
|
/**
|
|
2818
2955
|
* @param {!Task} task The task to drop.
|
|
2819
2956
|
* @private
|
|
2820
2957
|
*/
|
|
2821
|
-
dropTask_
|
|
2958
|
+
dropTask_(task) {
|
|
2822
2959
|
var index;
|
|
2823
2960
|
if (this.interrupts_) {
|
|
2824
2961
|
index = this.interrupts_.indexOf(task);
|
|
@@ -2834,49 +2971,49 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2834
2971
|
task.queue = null;
|
|
2835
2972
|
this.tasks_.splice(index, 1);
|
|
2836
2973
|
}
|
|
2837
|
-
}
|
|
2974
|
+
}
|
|
2838
2975
|
|
|
2839
2976
|
/**
|
|
2840
2977
|
* @param {!Task} task The task that was cancelled.
|
|
2841
|
-
* @param {!
|
|
2978
|
+
* @param {!CancellationError} reason The cancellation reason.
|
|
2842
2979
|
* @private
|
|
2843
2980
|
*/
|
|
2844
|
-
onTaskCancelled_
|
|
2981
|
+
onTaskCancelled_(task, reason) {
|
|
2845
2982
|
if (this.pending_ && this.pending_.task === task) {
|
|
2846
2983
|
this.pending_.q.abort_(reason);
|
|
2847
2984
|
} else {
|
|
2848
2985
|
this.dropTask_(task);
|
|
2849
2986
|
}
|
|
2850
|
-
}
|
|
2987
|
+
}
|
|
2851
2988
|
|
|
2852
2989
|
/**
|
|
2853
2990
|
* @param {*} value the value originally returned by the task function.
|
|
2854
2991
|
* @private
|
|
2855
2992
|
*/
|
|
2856
|
-
onTaskComplete_
|
|
2993
|
+
onTaskComplete_(value) {
|
|
2857
2994
|
if (this.pending_) {
|
|
2858
2995
|
this.pending_.task.fulfill(value);
|
|
2859
2996
|
}
|
|
2860
|
-
}
|
|
2997
|
+
}
|
|
2861
2998
|
|
|
2862
2999
|
/**
|
|
2863
3000
|
* @param {*} taskFnResult the value originally returned by the task function.
|
|
2864
3001
|
* @param {*} error the error that caused the task function to terminate.
|
|
2865
3002
|
* @private
|
|
2866
3003
|
*/
|
|
2867
|
-
onTaskFailure_
|
|
2868
|
-
if (
|
|
2869
|
-
taskFnResult.cancel(
|
|
3004
|
+
onTaskFailure_(taskFnResult, error) {
|
|
3005
|
+
if (Thenable.isImplementation(taskFnResult)) {
|
|
3006
|
+
taskFnResult.cancel(CancellationError.wrap(error));
|
|
2870
3007
|
}
|
|
2871
3008
|
this.pending_.task.reject(error);
|
|
2872
|
-
}
|
|
3009
|
+
}
|
|
2873
3010
|
|
|
2874
3011
|
/**
|
|
2875
3012
|
* @return {(Task|undefined)} the next task scheduled within this queue,
|
|
2876
3013
|
* if any.
|
|
2877
3014
|
* @private
|
|
2878
3015
|
*/
|
|
2879
|
-
getNextTask_
|
|
3016
|
+
getNextTask_() {
|
|
2880
3017
|
var task = undefined;
|
|
2881
3018
|
while (true) {
|
|
2882
3019
|
if (this.interrupts_) {
|
|
@@ -2896,15 +3033,15 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2896
3033
|
}
|
|
2897
3034
|
return task;
|
|
2898
3035
|
}
|
|
2899
|
-
}
|
|
3036
|
+
};
|
|
2900
3037
|
|
|
2901
3038
|
|
|
2902
3039
|
|
|
2903
3040
|
/**
|
|
2904
3041
|
* The default flow to use if no others are active.
|
|
2905
|
-
* @type {!
|
|
3042
|
+
* @type {!ControlFlow}
|
|
2906
3043
|
*/
|
|
2907
|
-
var defaultFlow = new
|
|
3044
|
+
var defaultFlow = new ControlFlow();
|
|
2908
3045
|
|
|
2909
3046
|
|
|
2910
3047
|
/**
|
|
@@ -2912,48 +3049,48 @@ var defaultFlow = new promise.ControlFlow();
|
|
|
2912
3049
|
* commands. When there are multiple flows on the stack, the flow at index N
|
|
2913
3050
|
* represents a callback triggered within a task owned by the flow at index
|
|
2914
3051
|
* N-1.
|
|
2915
|
-
* @type {!Array<!
|
|
3052
|
+
* @type {!Array<!ControlFlow>}
|
|
2916
3053
|
*/
|
|
2917
3054
|
var activeFlows = [];
|
|
2918
3055
|
|
|
2919
3056
|
|
|
2920
3057
|
/**
|
|
2921
3058
|
* Changes the default flow to use when no others are active.
|
|
2922
|
-
* @param {!
|
|
3059
|
+
* @param {!ControlFlow} flow The new default flow.
|
|
2923
3060
|
* @throws {Error} If the default flow is not currently active.
|
|
2924
3061
|
*/
|
|
2925
|
-
|
|
3062
|
+
function setDefaultFlow(flow) {
|
|
2926
3063
|
if (activeFlows.length) {
|
|
2927
3064
|
throw Error('You may only change the default flow while it is active');
|
|
2928
3065
|
}
|
|
2929
3066
|
defaultFlow = flow;
|
|
2930
|
-
}
|
|
3067
|
+
}
|
|
2931
3068
|
|
|
2932
3069
|
|
|
2933
3070
|
/**
|
|
2934
|
-
* @return {!
|
|
3071
|
+
* @return {!ControlFlow} The currently active control flow.
|
|
2935
3072
|
*/
|
|
2936
|
-
|
|
2937
|
-
return /** @type {!
|
|
2938
|
-
|
|
2939
|
-
}
|
|
3073
|
+
function controlFlow() {
|
|
3074
|
+
return /** @type {!ControlFlow} */ (
|
|
3075
|
+
activeFlows.length ? activeFlows[activeFlows.length - 1] : defaultFlow);
|
|
3076
|
+
}
|
|
2940
3077
|
|
|
2941
3078
|
|
|
2942
3079
|
/**
|
|
2943
3080
|
* Creates a new control flow. The provided callback will be invoked as the
|
|
2944
3081
|
* first task within the new flow, with the flow as its sole argument. Returns
|
|
2945
3082
|
* a promise that resolves to the callback result.
|
|
2946
|
-
* @param {function(!
|
|
3083
|
+
* @param {function(!ControlFlow)} callback The entry point
|
|
2947
3084
|
* to the newly created flow.
|
|
2948
|
-
* @return {!
|
|
3085
|
+
* @return {!ManagedPromise} A promise that resolves to the callback
|
|
2949
3086
|
* result.
|
|
2950
3087
|
*/
|
|
2951
|
-
|
|
2952
|
-
var flow = new
|
|
3088
|
+
function createFlow(callback) {
|
|
3089
|
+
var flow = new ControlFlow;
|
|
2953
3090
|
return flow.execute(function() {
|
|
2954
3091
|
return callback(flow);
|
|
2955
3092
|
});
|
|
2956
|
-
}
|
|
3093
|
+
}
|
|
2957
3094
|
|
|
2958
3095
|
|
|
2959
3096
|
/**
|
|
@@ -2961,9 +3098,9 @@ promise.createFlow = function(callback) {
|
|
|
2961
3098
|
* @param {!Function} fn The function to test.
|
|
2962
3099
|
* @return {boolean} Whether the function is a generator.
|
|
2963
3100
|
*/
|
|
2964
|
-
|
|
3101
|
+
function isGenerator(fn) {
|
|
2965
3102
|
return fn.constructor.name === 'GeneratorFunction';
|
|
2966
|
-
}
|
|
3103
|
+
}
|
|
2967
3104
|
|
|
2968
3105
|
|
|
2969
3106
|
/**
|
|
@@ -2992,7 +3129,7 @@ promise.isGenerator = function(fn) {
|
|
|
2992
3129
|
* yield promise.delayed(250).then(function() {
|
|
2993
3130
|
* throw Error('boom');
|
|
2994
3131
|
* });
|
|
2995
|
-
* }).
|
|
3132
|
+
* }).catch(function(e) {
|
|
2996
3133
|
* console.log(e.toString()); // Error: boom
|
|
2997
3134
|
* });
|
|
2998
3135
|
*
|
|
@@ -3000,18 +3137,19 @@ promise.isGenerator = function(fn) {
|
|
|
3000
3137
|
* @param {Object=} opt_self The object to use as "this" when invoking the
|
|
3001
3138
|
* initial generator.
|
|
3002
3139
|
* @param {...*} var_args Any arguments to pass to the initial generator.
|
|
3003
|
-
* @return {!
|
|
3140
|
+
* @return {!ManagedPromise<?>} A promise that will resolve to the
|
|
3004
3141
|
* generator's final result.
|
|
3005
3142
|
* @throws {TypeError} If the given function is not a generator.
|
|
3006
3143
|
*/
|
|
3007
|
-
|
|
3008
|
-
if (!
|
|
3144
|
+
function consume(generatorFn, opt_self, var_args) {
|
|
3145
|
+
if (!isGenerator(generatorFn)) {
|
|
3009
3146
|
throw new TypeError('Input is not a GeneratorFunction: ' +
|
|
3010
3147
|
generatorFn.constructor.name);
|
|
3011
3148
|
}
|
|
3012
3149
|
|
|
3013
|
-
var deferred =
|
|
3014
|
-
var generator = generatorFn.apply(
|
|
3150
|
+
var deferred = defer();
|
|
3151
|
+
var generator = generatorFn.apply(
|
|
3152
|
+
opt_self, Array.prototype.slice.call(arguments, 2));
|
|
3015
3153
|
callNext();
|
|
3016
3154
|
return deferred.promise;
|
|
3017
3155
|
|
|
@@ -3044,6 +3182,41 @@ promise.consume = function(generatorFn, opt_self, var_args) {
|
|
|
3044
3182
|
return;
|
|
3045
3183
|
}
|
|
3046
3184
|
|
|
3047
|
-
|
|
3185
|
+
asap(result.value, callNext, callThrow);
|
|
3048
3186
|
}
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
|
|
3190
|
+
// PUBLIC API
|
|
3191
|
+
|
|
3192
|
+
|
|
3193
|
+
module.exports = {
|
|
3194
|
+
CancellationError: CancellationError,
|
|
3195
|
+
ControlFlow: ControlFlow,
|
|
3196
|
+
Deferred: Deferred,
|
|
3197
|
+
MultipleUnhandledRejectionError: MultipleUnhandledRejectionError,
|
|
3198
|
+
Thenable: Thenable,
|
|
3199
|
+
Promise: ManagedPromise,
|
|
3200
|
+
all: all,
|
|
3201
|
+
asap: asap,
|
|
3202
|
+
captureStackTrace: captureStackTrace,
|
|
3203
|
+
checkedNodeCall: checkedNodeCall,
|
|
3204
|
+
consume: consume,
|
|
3205
|
+
controlFlow: controlFlow,
|
|
3206
|
+
createFlow: createFlow,
|
|
3207
|
+
defer: defer,
|
|
3208
|
+
delayed: delayed,
|
|
3209
|
+
filter: filter,
|
|
3210
|
+
fulfilled: fulfilled,
|
|
3211
|
+
fullyResolved: fullyResolved,
|
|
3212
|
+
isGenerator: isGenerator,
|
|
3213
|
+
isPromise: isPromise,
|
|
3214
|
+
map: map,
|
|
3215
|
+
rejected: rejected,
|
|
3216
|
+
setDefaultFlow: setDefaultFlow,
|
|
3217
|
+
thenFinally: thenFinally,
|
|
3218
|
+
when: when,
|
|
3219
|
+
|
|
3220
|
+
get LONG_STACK_TRACES() { return LONG_STACK_TRACES; },
|
|
3221
|
+
set LONG_STACK_TRACES(v) { LONG_STACK_TRACES = v; },
|
|
3049
3222
|
};
|