selenium-webdriver 2.48.2 → 2.52.0
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 +57 -0
- package/NOTICE +1 -1
- package/README.md +56 -6
- package/builder.js +375 -358
- package/chrome.js +549 -586
- package/edge.js +378 -0
- package/error.js +597 -5
- package/example/google_search_generator.js +2 -4
- package/example/logging.js +6 -2
- package/executors.js +11 -27
- package/firefox/binary.js +79 -87
- package/firefox/extension.js +10 -18
- package/firefox/index.js +173 -173
- package/firefox/profile.js +220 -240
- package/http/index.js +396 -79
- package/http/util.js +35 -35
- package/ie.js +288 -309
- package/index.js +34 -125
- package/io/exec.js +58 -39
- package/io/index.js +54 -48
- package/lib/actions.js +594 -0
- package/lib/by.js +276 -0
- package/lib/capabilities.js +404 -0
- package/lib/{webdriver/command.js → command.js} +88 -72
- package/lib/{webdriver/button.js → devmode.js} +13 -8
- package/lib/events.js +210 -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} +82 -2
- package/lib/logging.js +668 -0
- package/lib/{webdriver/promise.js → promise.js} +688 -644
- package/lib/session.js +79 -0
- package/lib/{webdriver/serializable.js → symbols.js} +11 -16
- 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/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 +428 -0
- package/lib/webdriver.js +2351 -0
- package/net/portprober.js +15 -11
- package/opera.js +295 -314
- package/package.json +6 -5
- package/phantomjs.js +135 -140
- package/proxy.js +6 -4
- package/remote/index.js +229 -221
- package/safari.js +319 -310
- package/test/chrome/options_test.js +11 -9
- package/test/element_finding_test.js +51 -13
- package/test/error_test.js +163 -0
- package/test/execute_script_test.js +1 -1
- package/test/http/http_test.js +317 -55
- package/test/http/util_test.js +25 -23
- package/test/io_test.js +6 -1
- package/test/lib/by_test.js +127 -0
- package/test/lib/capabilities_test.js +84 -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 +436 -0
- package/test/lib/webdriver_test.js +2207 -0
- package/test/page_loading_test.js +7 -9
- 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 +10 -0
- 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
|
-
|
|
593
|
+
'use strict';
|
|
594
|
+
|
|
595
|
+
const events = require('./events');
|
|
596
|
+
const logging = require('./logging');
|
|
629
597
|
|
|
630
|
-
var Arrays = goog.require('goog.array');
|
|
631
|
-
var asserts = goog.require('goog.asserts');
|
|
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');
|
|
639
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Alias to help with readability and differentiate types.
|
|
601
|
+
* @const
|
|
602
|
+
*/
|
|
603
|
+
const NativePromise = Promise;
|
|
640
604
|
|
|
641
605
|
|
|
642
606
|
/**
|
|
643
|
-
*
|
|
644
|
-
*
|
|
607
|
+
* Whether to append traces of `then` to rejection errors.
|
|
608
|
+
* @type {boolean}
|
|
645
609
|
*/
|
|
646
|
-
|
|
610
|
+
exports.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,30 @@ 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
|
+
* @template R
|
|
922
|
+
*/
|
|
923
|
+
thenCatch(errback) {}
|
|
935
924
|
|
|
936
925
|
/**
|
|
937
926
|
* Registers a listener to invoke when this promise is resolved, regardless
|
|
@@ -965,19 +954,18 @@ promise.Thenable = goog.defineClass(null, {
|
|
|
965
954
|
*
|
|
966
955
|
* @param {function(): (R|IThenable<R>)} callback The function
|
|
967
956
|
* to call when this promise is resolved.
|
|
968
|
-
* @return {!
|
|
957
|
+
* @return {!ManagedPromise<R>} A promise that will be fulfilled
|
|
969
958
|
* with the callback result.
|
|
970
959
|
* @template R
|
|
971
960
|
*/
|
|
972
|
-
thenFinally
|
|
973
|
-
}
|
|
974
|
-
|
|
961
|
+
thenFinally(callback) {}
|
|
962
|
+
}
|
|
975
963
|
|
|
976
964
|
|
|
977
965
|
/**
|
|
978
966
|
* @enum {string}
|
|
979
967
|
*/
|
|
980
|
-
|
|
968
|
+
const PromiseState = {
|
|
981
969
|
PENDING: 'pending',
|
|
982
970
|
BLOCKED: 'blocked',
|
|
983
971
|
REJECTED: 'rejected',
|
|
@@ -987,11 +975,11 @@ var PromiseState = {
|
|
|
987
975
|
|
|
988
976
|
/**
|
|
989
977
|
* Internal symbol used to store a cancellation handler for
|
|
990
|
-
* {@link
|
|
978
|
+
* {@link ManagedPromise} objects. This is an internal implementation detail
|
|
991
979
|
* used by the {@link TaskQueue} class to monitor for when a promise is
|
|
992
980
|
* cancelled without generating an extra promise via then().
|
|
993
981
|
*/
|
|
994
|
-
|
|
982
|
+
const CANCEL_HANDLER_SYMBOL = Symbol('on cancel');
|
|
995
983
|
|
|
996
984
|
|
|
997
985
|
/**
|
|
@@ -1001,12 +989,12 @@ var CANCEL_HANDLER_SYMBOL = Symbol('on cancel');
|
|
|
1001
989
|
* fulfilled or rejected state, at which point the promise is considered
|
|
1002
990
|
* resolved.
|
|
1003
991
|
*
|
|
1004
|
-
* @implements {
|
|
992
|
+
* @implements {Thenable<T>}
|
|
993
|
+
* @unrestricted
|
|
1005
994
|
* @template T
|
|
1006
995
|
* @see http://promises-aplus.github.io/promises-spec/
|
|
1007
|
-
* @unrestricted // For using CANCEL_HANDLER_SYMBOL.
|
|
1008
996
|
*/
|
|
1009
|
-
|
|
997
|
+
const ManagedPromise = class Promise {
|
|
1010
998
|
/**
|
|
1011
999
|
* @param {function(
|
|
1012
1000
|
* function((T|IThenable<T>|Thenable)=),
|
|
@@ -1014,23 +1002,22 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1014
1002
|
* Function that is invoked immediately to begin computation of this
|
|
1015
1003
|
* promise's value. The function should accept a pair of callback
|
|
1016
1004
|
* functions, one for fulfilling the promise and another for rejecting it.
|
|
1017
|
-
* @param {
|
|
1005
|
+
* @param {ControlFlow=} opt_flow The control flow
|
|
1018
1006
|
* this instance was created under. Defaults to the currently active flow.
|
|
1019
1007
|
*/
|
|
1020
|
-
constructor
|
|
1021
|
-
|
|
1008
|
+
constructor(resolver, opt_flow) {
|
|
1009
|
+
getUid(this);
|
|
1022
1010
|
|
|
1023
|
-
/** @private {!
|
|
1024
|
-
this.flow_ = opt_flow ||
|
|
1011
|
+
/** @private {!ControlFlow} */
|
|
1012
|
+
this.flow_ = opt_flow || controlFlow();
|
|
1025
1013
|
|
|
1026
1014
|
/** @private {Error} */
|
|
1027
1015
|
this.stack_ = null;
|
|
1028
|
-
if (
|
|
1029
|
-
this.stack_ =
|
|
1030
|
-
'Promise', 'new', promise.Promise);
|
|
1016
|
+
if (exports.LONG_STACK_TRACES) {
|
|
1017
|
+
this.stack_ = captureStackTrace('Promise', 'new', this.constructor);
|
|
1031
1018
|
}
|
|
1032
1019
|
|
|
1033
|
-
/** @private {
|
|
1020
|
+
/** @private {ManagedPromise<?>} */
|
|
1034
1021
|
this.parent_ = null;
|
|
1035
1022
|
|
|
1036
1023
|
/** @private {Array<!Task>} */
|
|
@@ -1048,7 +1035,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1048
1035
|
/** @private {TaskQueue} */
|
|
1049
1036
|
this.queue_ = null;
|
|
1050
1037
|
|
|
1051
|
-
/** @private {(function(
|
|
1038
|
+
/** @private {(function(CancellationError)|null)} */
|
|
1052
1039
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
1053
1040
|
|
|
1054
1041
|
try {
|
|
@@ -1061,13 +1048,13 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1061
1048
|
} catch (ex) {
|
|
1062
1049
|
this.resolve_(PromiseState.REJECTED, ex);
|
|
1063
1050
|
}
|
|
1064
|
-
}
|
|
1051
|
+
}
|
|
1065
1052
|
|
|
1066
1053
|
/** @override */
|
|
1067
|
-
toString
|
|
1068
|
-
return '
|
|
1054
|
+
toString() {
|
|
1055
|
+
return 'ManagedPromise::' + getUid(this) +
|
|
1069
1056
|
' {[[PromiseStatus]]: "' + this.state_ + '"}';
|
|
1070
|
-
}
|
|
1057
|
+
}
|
|
1071
1058
|
|
|
1072
1059
|
/**
|
|
1073
1060
|
* Resolves this promise. If the new value is itself a promise, this function
|
|
@@ -1077,7 +1064,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1077
1064
|
* @throws {TypeError} If {@code newValue === this}.
|
|
1078
1065
|
* @private
|
|
1079
1066
|
*/
|
|
1080
|
-
resolve_
|
|
1067
|
+
resolve_(newState, newValue) {
|
|
1081
1068
|
if (PromiseState.PENDING !== this.state_) {
|
|
1082
1069
|
return;
|
|
1083
1070
|
}
|
|
@@ -1093,15 +1080,16 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1093
1080
|
this.state_ = PromiseState.BLOCKED;
|
|
1094
1081
|
|
|
1095
1082
|
if (newState !== PromiseState.REJECTED) {
|
|
1096
|
-
if (
|
|
1083
|
+
if (Thenable.isImplementation(newValue)) {
|
|
1097
1084
|
// 2.3.2
|
|
1098
|
-
newValue = /** @type {!
|
|
1085
|
+
newValue = /** @type {!Thenable} */(newValue);
|
|
1099
1086
|
newValue.then(
|
|
1100
1087
|
this.unblockAndResolve_.bind(this, PromiseState.FULFILLED),
|
|
1101
1088
|
this.unblockAndResolve_.bind(this, PromiseState.REJECTED));
|
|
1102
1089
|
return;
|
|
1103
1090
|
|
|
1104
|
-
} else if (
|
|
1091
|
+
} else if (newValue
|
|
1092
|
+
&& (typeof newValue === 'object' || typeof newValue === 'function')) {
|
|
1105
1093
|
// 2.3.3
|
|
1106
1094
|
|
|
1107
1095
|
try {
|
|
@@ -1115,10 +1103,9 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1115
1103
|
return;
|
|
1116
1104
|
}
|
|
1117
1105
|
|
|
1118
|
-
// NB: goog.isFunction is loose and will accept instanceof Function.
|
|
1119
1106
|
if (typeof then === 'function') {
|
|
1120
1107
|
// 2.3.3.3
|
|
1121
|
-
this.invokeThen_(newValue, then);
|
|
1108
|
+
this.invokeThen_(/** @type {!Object} */(newValue), then);
|
|
1122
1109
|
return;
|
|
1123
1110
|
}
|
|
1124
1111
|
}
|
|
@@ -1133,7 +1120,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1133
1120
|
this.state_ = newState;
|
|
1134
1121
|
this.value_ = newValue;
|
|
1135
1122
|
this.scheduleNotifications_();
|
|
1136
|
-
}
|
|
1123
|
+
}
|
|
1137
1124
|
|
|
1138
1125
|
/**
|
|
1139
1126
|
* Invokes a thenable's "then" method according to 2.3.3.3 of the promise
|
|
@@ -1142,7 +1129,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1142
1129
|
* @param {!Function} then The "then" function to invoke.
|
|
1143
1130
|
* @private
|
|
1144
1131
|
*/
|
|
1145
|
-
invokeThen_
|
|
1132
|
+
invokeThen_(x, then) {
|
|
1146
1133
|
var called = false;
|
|
1147
1134
|
var self = this;
|
|
1148
1135
|
|
|
@@ -1169,28 +1156,28 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1169
1156
|
// 2.3.3.3.4.2
|
|
1170
1157
|
rejectPromise(e);
|
|
1171
1158
|
}
|
|
1172
|
-
}
|
|
1159
|
+
}
|
|
1173
1160
|
|
|
1174
1161
|
/**
|
|
1175
1162
|
* @param {PromiseState} newState The promise's new state.
|
|
1176
1163
|
* @param {*} newValue The promise's new value.
|
|
1177
1164
|
* @private
|
|
1178
1165
|
*/
|
|
1179
|
-
unblockAndResolve_
|
|
1166
|
+
unblockAndResolve_(newState, newValue) {
|
|
1180
1167
|
if (this.state_ === PromiseState.BLOCKED) {
|
|
1181
1168
|
this.state_ = PromiseState.PENDING;
|
|
1182
1169
|
this.resolve_(newState, newValue);
|
|
1183
1170
|
}
|
|
1184
|
-
}
|
|
1171
|
+
}
|
|
1185
1172
|
|
|
1186
1173
|
/**
|
|
1187
1174
|
* @private
|
|
1188
1175
|
*/
|
|
1189
|
-
scheduleNotifications_
|
|
1176
|
+
scheduleNotifications_() {
|
|
1190
1177
|
vlog(2, () => this + ' scheduling notifications', this);
|
|
1191
1178
|
|
|
1192
1179
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
1193
|
-
if (this.value_ instanceof
|
|
1180
|
+
if (this.value_ instanceof CancellationError
|
|
1194
1181
|
&& this.value_.silent_) {
|
|
1195
1182
|
this.callbacks_ = null;
|
|
1196
1183
|
}
|
|
@@ -1201,14 +1188,14 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1201
1188
|
|
|
1202
1189
|
if (!this.handled_ &&
|
|
1203
1190
|
this.state_ === PromiseState.REJECTED &&
|
|
1204
|
-
!(this.value_ instanceof
|
|
1191
|
+
!(this.value_ instanceof CancellationError)) {
|
|
1205
1192
|
this.queue_.addUnhandledRejection(this);
|
|
1206
1193
|
}
|
|
1207
1194
|
this.queue_.scheduleCallbacks(this);
|
|
1208
|
-
}
|
|
1195
|
+
}
|
|
1209
1196
|
|
|
1210
1197
|
/** @override */
|
|
1211
|
-
cancel
|
|
1198
|
+
cancel(opt_reason) {
|
|
1212
1199
|
if (!canCancel(this)) {
|
|
1213
1200
|
return;
|
|
1214
1201
|
}
|
|
@@ -1216,7 +1203,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1216
1203
|
if (this.parent_ && canCancel(this.parent_)) {
|
|
1217
1204
|
this.parent_.cancel(opt_reason);
|
|
1218
1205
|
} else {
|
|
1219
|
-
var reason =
|
|
1206
|
+
var reason = CancellationError.wrap(opt_reason);
|
|
1220
1207
|
if (this[CANCEL_HANDLER_SYMBOL]) {
|
|
1221
1208
|
this[CANCEL_HANDLER_SYMBOL](reason);
|
|
1222
1209
|
this[CANCEL_HANDLER_SYMBOL] = null;
|
|
@@ -1233,27 +1220,32 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1233
1220
|
return promise.state_ === PromiseState.PENDING
|
|
1234
1221
|
|| promise.state_ === PromiseState.BLOCKED;
|
|
1235
1222
|
}
|
|
1236
|
-
}
|
|
1223
|
+
}
|
|
1237
1224
|
|
|
1238
1225
|
/** @override */
|
|
1239
|
-
isPending
|
|
1226
|
+
isPending() {
|
|
1240
1227
|
return this.state_ === PromiseState.PENDING;
|
|
1241
|
-
}
|
|
1228
|
+
}
|
|
1242
1229
|
|
|
1243
1230
|
/** @override */
|
|
1244
|
-
then
|
|
1231
|
+
then(opt_callback, opt_errback) {
|
|
1245
1232
|
return this.addCallback_(
|
|
1246
|
-
opt_callback, opt_errback, 'then',
|
|
1247
|
-
}
|
|
1233
|
+
opt_callback, opt_errback, 'then', ManagedPromise.prototype.then);
|
|
1234
|
+
}
|
|
1248
1235
|
|
|
1249
1236
|
/** @override */
|
|
1250
|
-
|
|
1237
|
+
catch(errback) {
|
|
1251
1238
|
return this.addCallback_(
|
|
1252
|
-
null, errback, '
|
|
1253
|
-
}
|
|
1239
|
+
null, errback, 'catch', ManagedPromise.prototype.catch);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/** @override */
|
|
1243
|
+
thenCatch(errback) {
|
|
1244
|
+
return this.catch(errback);
|
|
1245
|
+
}
|
|
1254
1246
|
|
|
1255
1247
|
/** @override */
|
|
1256
|
-
thenFinally
|
|
1248
|
+
thenFinally(callback) {
|
|
1257
1249
|
var error;
|
|
1258
1250
|
var mustThrow = false;
|
|
1259
1251
|
return this.then(function() {
|
|
@@ -1267,7 +1259,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1267
1259
|
throw error;
|
|
1268
1260
|
}
|
|
1269
1261
|
});
|
|
1270
|
-
}
|
|
1262
|
+
}
|
|
1271
1263
|
|
|
1272
1264
|
/**
|
|
1273
1265
|
* Registers a new callback with this promise
|
|
@@ -1278,13 +1270,13 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1278
1270
|
* @param {string} name The callback name.
|
|
1279
1271
|
* @param {!Function} fn The function to use as the top of the stack when
|
|
1280
1272
|
* recording the callback's creation point.
|
|
1281
|
-
* @return {!
|
|
1273
|
+
* @return {!ManagedPromise<R>} A new promise which will be resolved with the
|
|
1282
1274
|
* esult of the invoked callback.
|
|
1283
1275
|
* @template R
|
|
1284
1276
|
* @private
|
|
1285
1277
|
*/
|
|
1286
|
-
addCallback_
|
|
1287
|
-
if (
|
|
1278
|
+
addCallback_(callback, errback, name, fn) {
|
|
1279
|
+
if (typeof callback !== 'function' && typeof errback !== 'function') {
|
|
1288
1280
|
return this;
|
|
1289
1281
|
}
|
|
1290
1282
|
|
|
@@ -1297,7 +1289,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1297
1289
|
this.flow_,
|
|
1298
1290
|
this.invokeCallback_.bind(this, callback, errback),
|
|
1299
1291
|
name,
|
|
1300
|
-
|
|
1292
|
+
exports.LONG_STACK_TRACES ? {name: 'Promise', top: fn} : undefined);
|
|
1301
1293
|
cb.promise.parent_ = this;
|
|
1302
1294
|
|
|
1303
1295
|
if (this.state_ !== PromiseState.PENDING &&
|
|
@@ -1313,7 +1305,7 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1313
1305
|
}
|
|
1314
1306
|
|
|
1315
1307
|
return cb.promise;
|
|
1316
|
-
}
|
|
1308
|
+
}
|
|
1317
1309
|
|
|
1318
1310
|
/**
|
|
1319
1311
|
* Invokes a callback function attached to this promise.
|
|
@@ -1324,15 +1316,15 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1324
1316
|
* @template R
|
|
1325
1317
|
* @private
|
|
1326
1318
|
*/
|
|
1327
|
-
invokeCallback_
|
|
1319
|
+
invokeCallback_(callback, errback) {
|
|
1328
1320
|
var callbackFn = callback;
|
|
1329
1321
|
if (this.state_ === PromiseState.REJECTED) {
|
|
1330
1322
|
callbackFn = errback;
|
|
1331
1323
|
}
|
|
1332
1324
|
|
|
1333
|
-
if (
|
|
1334
|
-
if (
|
|
1335
|
-
return
|
|
1325
|
+
if (typeof callbackFn === 'function') {
|
|
1326
|
+
if (isGenerator(callbackFn)) {
|
|
1327
|
+
return consume(callbackFn, null, this.value_);
|
|
1336
1328
|
}
|
|
1337
1329
|
return callbackFn(this.value_);
|
|
1338
1330
|
} else if (this.state_ === PromiseState.REJECTED) {
|
|
@@ -1341,34 +1333,34 @@ promise.Promise = goog.defineClass(null, {
|
|
|
1341
1333
|
return this.value_;
|
|
1342
1334
|
}
|
|
1343
1335
|
}
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1336
|
+
}
|
|
1337
|
+
Thenable.addImplementation(ManagedPromise);
|
|
1346
1338
|
|
|
1347
1339
|
|
|
1348
1340
|
/**
|
|
1349
1341
|
* Represents a value that will be resolved at some point in the future. This
|
|
1350
|
-
* class represents the protected "producer" half of a
|
|
1342
|
+
* class represents the protected "producer" half of a ManagedPromise - each Deferred
|
|
1351
1343
|
* has a {@code promise} property that may be returned to consumers for
|
|
1352
1344
|
* registering callbacks, reserving the ability to resolve the deferred to the
|
|
1353
1345
|
* producer.
|
|
1354
1346
|
*
|
|
1355
1347
|
* If this Deferred is rejected and there are no listeners registered before
|
|
1356
1348
|
* the next turn of the event loop, the rejection will be passed to the
|
|
1357
|
-
* {@link
|
|
1349
|
+
* {@link ControlFlow} as an unhandled failure.
|
|
1358
1350
|
*
|
|
1359
|
-
* @implements {
|
|
1351
|
+
* @implements {Thenable<T>}
|
|
1360
1352
|
* @template T
|
|
1361
1353
|
*/
|
|
1362
|
-
|
|
1354
|
+
class Deferred {
|
|
1363
1355
|
/**
|
|
1364
|
-
* @param {
|
|
1356
|
+
* @param {ControlFlow=} opt_flow The control flow this instance was
|
|
1365
1357
|
* created under. This should only be provided during unit tests.
|
|
1366
1358
|
*/
|
|
1367
|
-
constructor
|
|
1359
|
+
constructor(opt_flow) {
|
|
1368
1360
|
var fulfill, reject;
|
|
1369
1361
|
|
|
1370
|
-
/** @type {!
|
|
1371
|
-
this.promise = new
|
|
1362
|
+
/** @type {!ManagedPromise<T>} */
|
|
1363
|
+
this.promise = new ManagedPromise(function(f, r) {
|
|
1372
1364
|
fulfill = f;
|
|
1373
1365
|
reject = r;
|
|
1374
1366
|
}, opt_flow);
|
|
@@ -1399,43 +1391,51 @@ promise.Deferred = goog.defineClass(null, {
|
|
|
1399
1391
|
checkNotSelf(opt_reason);
|
|
1400
1392
|
reject(opt_reason);
|
|
1401
1393
|
};
|
|
1402
|
-
}
|
|
1394
|
+
}
|
|
1403
1395
|
|
|
1404
1396
|
/** @override */
|
|
1405
|
-
isPending
|
|
1397
|
+
isPending() {
|
|
1406
1398
|
return this.promise.isPending();
|
|
1407
|
-
}
|
|
1399
|
+
}
|
|
1408
1400
|
|
|
1409
1401
|
/** @override */
|
|
1410
|
-
cancel
|
|
1402
|
+
cancel(opt_reason) {
|
|
1411
1403
|
this.promise.cancel(opt_reason);
|
|
1412
|
-
}
|
|
1404
|
+
}
|
|
1413
1405
|
|
|
1414
1406
|
/**
|
|
1415
1407
|
* @override
|
|
1416
1408
|
* @deprecated Use {@code then} from the promise property directly.
|
|
1417
1409
|
*/
|
|
1418
|
-
then
|
|
1410
|
+
then(opt_cb, opt_eb) {
|
|
1419
1411
|
return this.promise.then(opt_cb, opt_eb);
|
|
1420
|
-
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
/**
|
|
1415
|
+
* @override
|
|
1416
|
+
* @deprecated Use {@lcode catch} from the promise property directly.
|
|
1417
|
+
*/
|
|
1418
|
+
catch(opt_eb) {
|
|
1419
|
+
return this.promise.catch(opt_eb);
|
|
1420
|
+
}
|
|
1421
1421
|
|
|
1422
1422
|
/**
|
|
1423
1423
|
* @override
|
|
1424
1424
|
* @deprecated Use {@code thenCatch} from the promise property directly.
|
|
1425
1425
|
*/
|
|
1426
|
-
thenCatch
|
|
1426
|
+
thenCatch(opt_eb) {
|
|
1427
1427
|
return this.promise.thenCatch(opt_eb);
|
|
1428
|
-
}
|
|
1428
|
+
}
|
|
1429
1429
|
|
|
1430
1430
|
/**
|
|
1431
1431
|
* @override
|
|
1432
1432
|
* @deprecated Use {@code thenFinally} from the promise property directly.
|
|
1433
1433
|
*/
|
|
1434
|
-
thenFinally
|
|
1434
|
+
thenFinally(opt_cb) {
|
|
1435
1435
|
return this.promise.thenFinally(opt_cb);
|
|
1436
1436
|
}
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1437
|
+
}
|
|
1438
|
+
Thenable.addImplementation(Deferred);
|
|
1439
1439
|
|
|
1440
1440
|
|
|
1441
1441
|
/**
|
|
@@ -1446,11 +1446,8 @@ promise.Thenable.addImplementation(promise.Deferred);
|
|
|
1446
1446
|
*/
|
|
1447
1447
|
function isError(value) {
|
|
1448
1448
|
return value instanceof Error ||
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
// A special test for goog.testing.JsUnitException.
|
|
1452
|
-
value.isJsUnitException);
|
|
1453
|
-
|
|
1449
|
+
(!!value && typeof value === 'object'
|
|
1450
|
+
&& typeof value.message === 'string');
|
|
1454
1451
|
}
|
|
1455
1452
|
|
|
1456
1453
|
|
|
@@ -1458,97 +1455,101 @@ function isError(value) {
|
|
|
1458
1455
|
* Determines whether a {@code value} should be treated as a promise.
|
|
1459
1456
|
* Any object whose "then" property is a function will be considered a promise.
|
|
1460
1457
|
*
|
|
1461
|
-
* @param {
|
|
1458
|
+
* @param {?} value The value to test.
|
|
1462
1459
|
* @return {boolean} Whether the value is a promise.
|
|
1463
1460
|
*/
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
}
|
|
1461
|
+
function isPromise(value) {
|
|
1462
|
+
try {
|
|
1463
|
+
// Use array notation so the Closure compiler does not obfuscate away our
|
|
1464
|
+
// contract.
|
|
1465
|
+
return value
|
|
1466
|
+
&& (typeof value === 'object' || typeof value === 'function')
|
|
1467
|
+
&& typeof value['then'] === 'function';
|
|
1468
|
+
} catch (ex) {
|
|
1469
|
+
return false;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
1472
|
|
|
1473
1473
|
|
|
1474
1474
|
/**
|
|
1475
1475
|
* Creates a promise that will be resolved at a set time in the future.
|
|
1476
1476
|
* @param {number} ms The amount of time, in milliseconds, to wait before
|
|
1477
1477
|
* resolving the promise.
|
|
1478
|
-
* @return {!
|
|
1478
|
+
* @return {!ManagedPromise} The promise.
|
|
1479
1479
|
*/
|
|
1480
|
-
|
|
1480
|
+
function delayed(ms) {
|
|
1481
1481
|
var key;
|
|
1482
|
-
return new
|
|
1482
|
+
return new ManagedPromise(function(fulfill) {
|
|
1483
1483
|
key = setTimeout(function() {
|
|
1484
1484
|
key = null;
|
|
1485
1485
|
fulfill();
|
|
1486
1486
|
}, ms);
|
|
1487
|
-
}).
|
|
1487
|
+
}).catch(function(e) {
|
|
1488
1488
|
clearTimeout(key);
|
|
1489
1489
|
key = null;
|
|
1490
1490
|
throw e;
|
|
1491
1491
|
});
|
|
1492
|
-
}
|
|
1492
|
+
}
|
|
1493
1493
|
|
|
1494
1494
|
|
|
1495
1495
|
/**
|
|
1496
1496
|
* Creates a new deferred object.
|
|
1497
|
-
* @return {!
|
|
1497
|
+
* @return {!Deferred<T>} The new deferred object.
|
|
1498
1498
|
* @template T
|
|
1499
1499
|
*/
|
|
1500
|
-
|
|
1501
|
-
return new
|
|
1502
|
-
}
|
|
1500
|
+
function defer() {
|
|
1501
|
+
return new Deferred();
|
|
1502
|
+
}
|
|
1503
1503
|
|
|
1504
1504
|
|
|
1505
1505
|
/**
|
|
1506
1506
|
* Creates a promise that has been resolved with the given value.
|
|
1507
1507
|
* @param {T=} opt_value The resolved value.
|
|
1508
|
-
* @return {!
|
|
1508
|
+
* @return {!ManagedPromise<T>} The resolved promise.
|
|
1509
1509
|
* @template T
|
|
1510
1510
|
*/
|
|
1511
|
-
|
|
1512
|
-
if (opt_value instanceof
|
|
1511
|
+
function fulfilled(opt_value) {
|
|
1512
|
+
if (opt_value instanceof ManagedPromise) {
|
|
1513
1513
|
return opt_value;
|
|
1514
1514
|
}
|
|
1515
|
-
return new
|
|
1515
|
+
return new ManagedPromise(function(fulfill) {
|
|
1516
1516
|
fulfill(opt_value);
|
|
1517
1517
|
});
|
|
1518
|
-
}
|
|
1518
|
+
}
|
|
1519
1519
|
|
|
1520
1520
|
|
|
1521
1521
|
/**
|
|
1522
1522
|
* Creates a promise that has been rejected with the given reason.
|
|
1523
1523
|
* @param {*=} opt_reason The rejection reason; may be any value, but is
|
|
1524
1524
|
* usually an Error or a string.
|
|
1525
|
-
* @return {!
|
|
1525
|
+
* @return {!ManagedPromise<T>} The rejected promise.
|
|
1526
1526
|
* @template T
|
|
1527
1527
|
*/
|
|
1528
|
-
|
|
1529
|
-
if (opt_reason instanceof
|
|
1528
|
+
function rejected(opt_reason) {
|
|
1529
|
+
if (opt_reason instanceof ManagedPromise) {
|
|
1530
1530
|
return opt_reason;
|
|
1531
1531
|
}
|
|
1532
|
-
return new
|
|
1532
|
+
return new ManagedPromise(function(_, reject) {
|
|
1533
1533
|
reject(opt_reason);
|
|
1534
1534
|
});
|
|
1535
|
-
}
|
|
1535
|
+
}
|
|
1536
1536
|
|
|
1537
1537
|
|
|
1538
1538
|
/**
|
|
1539
1539
|
* Wraps a function that expects a node-style callback as its final
|
|
1540
1540
|
* argument. This callback expects two arguments: an error value (which will be
|
|
1541
1541
|
* 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
|
|
1542
|
+
* The callback will the resolve or reject the returned promise, based on its
|
|
1543
|
+
* arguments.
|
|
1543
1544
|
* @param {!Function} fn The function to wrap.
|
|
1544
1545
|
* @param {...?} var_args The arguments to apply to the function, excluding the
|
|
1545
1546
|
* final callback.
|
|
1546
|
-
* @return {!
|
|
1547
|
+
* @return {!ManagedPromise} A promise that will be resolved with the
|
|
1547
1548
|
* result of the provided function's callback.
|
|
1548
1549
|
*/
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
return new
|
|
1550
|
+
function checkedNodeCall(fn, var_args) {
|
|
1551
|
+
let args = Array.prototype.slice.call(arguments, 1);
|
|
1552
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1552
1553
|
try {
|
|
1553
1554
|
args.push(function(error, value) {
|
|
1554
1555
|
error ? reject(error) : fulfill(value);
|
|
@@ -1558,7 +1559,7 @@ promise.checkedNodeCall = function(fn, var_args) {
|
|
|
1558
1559
|
reject(ex);
|
|
1559
1560
|
}
|
|
1560
1561
|
});
|
|
1561
|
-
}
|
|
1562
|
+
}
|
|
1562
1563
|
|
|
1563
1564
|
|
|
1564
1565
|
/**
|
|
@@ -1570,43 +1571,37 @@ promise.checkedNodeCall = function(fn, var_args) {
|
|
|
1570
1571
|
* resolved successfully.
|
|
1571
1572
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1572
1573
|
* rejected.
|
|
1573
|
-
* @return {!
|
|
1574
|
+
* @return {!ManagedPromise} A new promise.
|
|
1574
1575
|
*/
|
|
1575
|
-
|
|
1576
|
-
if (
|
|
1576
|
+
function when(value, opt_callback, opt_errback) {
|
|
1577
|
+
if (Thenable.isImplementation(value)) {
|
|
1577
1578
|
return value.then(opt_callback, opt_errback);
|
|
1578
1579
|
}
|
|
1579
1580
|
|
|
1580
|
-
return new
|
|
1581
|
-
|
|
1581
|
+
return new ManagedPromise(function(fulfill) {
|
|
1582
|
+
fulfill(value);
|
|
1582
1583
|
}).then(opt_callback, opt_errback);
|
|
1583
|
-
}
|
|
1584
|
+
}
|
|
1584
1585
|
|
|
1585
1586
|
|
|
1586
1587
|
/**
|
|
1587
|
-
* Invokes the appropriate callback function as soon as a promised
|
|
1588
|
-
*
|
|
1589
|
-
*
|
|
1588
|
+
* Invokes the appropriate callback function as soon as a promised `value` is
|
|
1589
|
+
* resolved. This function is similar to `when()`, except it does not return
|
|
1590
|
+
* a new promise.
|
|
1590
1591
|
* @param {*} value The value to observe.
|
|
1591
1592
|
* @param {Function} callback The function to call when the value is
|
|
1592
1593
|
* resolved successfully.
|
|
1593
1594
|
* @param {Function=} opt_errback The function to call when the value is
|
|
1594
1595
|
* rejected.
|
|
1595
1596
|
*/
|
|
1596
|
-
|
|
1597
|
-
if (
|
|
1597
|
+
function asap(value, callback, opt_errback) {
|
|
1598
|
+
if (isPromise(value)) {
|
|
1598
1599
|
value.then(callback, opt_errback);
|
|
1599
1600
|
|
|
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
1601
|
} else if (callback) {
|
|
1607
1602
|
callback(value);
|
|
1608
1603
|
}
|
|
1609
|
-
}
|
|
1604
|
+
}
|
|
1610
1605
|
|
|
1611
1606
|
|
|
1612
1607
|
/**
|
|
@@ -1615,16 +1610,16 @@ promise.asap = function(value, callback, opt_errback) {
|
|
|
1615
1610
|
* input array's promises are rejected, the returned promise will be rejected
|
|
1616
1611
|
* with the same reason.
|
|
1617
1612
|
*
|
|
1618
|
-
* @param {!Array<(T|!
|
|
1613
|
+
* @param {!Array<(T|!ManagedPromise<T>)>} arr An array of
|
|
1619
1614
|
* promises to wait on.
|
|
1620
|
-
* @return {!
|
|
1615
|
+
* @return {!ManagedPromise<!Array<T>>} A promise that is
|
|
1621
1616
|
* fulfilled with an array containing the fulfilled values of the
|
|
1622
1617
|
* input array, or rejected with the same reason as the first
|
|
1623
1618
|
* rejected value.
|
|
1624
1619
|
* @template T
|
|
1625
1620
|
*/
|
|
1626
|
-
|
|
1627
|
-
return new
|
|
1621
|
+
function all(arr) {
|
|
1622
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1628
1623
|
var n = arr.length;
|
|
1629
1624
|
var values = [];
|
|
1630
1625
|
|
|
@@ -1642,11 +1637,17 @@ promise.all = function(arr) {
|
|
|
1642
1637
|
}
|
|
1643
1638
|
};
|
|
1644
1639
|
|
|
1640
|
+
function processPromise(index) {
|
|
1641
|
+
asap(arr[index], function(value) {
|
|
1642
|
+
onFulfilled(index, value);
|
|
1643
|
+
}, reject);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1645
1646
|
for (var i = 0; i < n; ++i) {
|
|
1646
|
-
|
|
1647
|
+
processPromise(i);
|
|
1647
1648
|
}
|
|
1648
1649
|
});
|
|
1649
|
-
}
|
|
1650
|
+
}
|
|
1650
1651
|
|
|
1651
1652
|
|
|
1652
1653
|
/**
|
|
@@ -1662,7 +1663,7 @@ promise.all = function(arr) {
|
|
|
1662
1663
|
* Only the first failure will be reported; all subsequent errors will be
|
|
1663
1664
|
* silently ignored.
|
|
1664
1665
|
*
|
|
1665
|
-
* @param {!(Array<TYPE>|
|
|
1666
|
+
* @param {!(Array<TYPE>|ManagedPromise<!Array<TYPE>>)} arr The
|
|
1666
1667
|
* array to iterator over, or a promise that will resolve to said array.
|
|
1667
1668
|
* @param {function(this: SELF, TYPE, number, !Array<TYPE>): ?} fn The
|
|
1668
1669
|
* function to call for each element in the array. This function should
|
|
@@ -1671,11 +1672,13 @@ promise.all = function(arr) {
|
|
|
1671
1672
|
* {@code fn}.
|
|
1672
1673
|
* @template TYPE, SELF
|
|
1673
1674
|
*/
|
|
1674
|
-
|
|
1675
|
-
return
|
|
1676
|
-
|
|
1675
|
+
function map(arr, fn, opt_self) {
|
|
1676
|
+
return fulfilled(arr).then(function(v) {
|
|
1677
|
+
if (!Array.isArray(v)) {
|
|
1678
|
+
throw TypeError('not an array');
|
|
1679
|
+
}
|
|
1677
1680
|
var arr = /** @type {!Array} */(v);
|
|
1678
|
-
return new
|
|
1681
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1679
1682
|
var n = arr.length;
|
|
1680
1683
|
var values = new Array(n);
|
|
1681
1684
|
(function processNext(i) {
|
|
@@ -1689,7 +1692,7 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1689
1692
|
return;
|
|
1690
1693
|
}
|
|
1691
1694
|
try {
|
|
1692
|
-
|
|
1695
|
+
asap(
|
|
1693
1696
|
fn.call(opt_self, arr[i], i, /** @type {!Array} */(arr)),
|
|
1694
1697
|
function(value) {
|
|
1695
1698
|
values[i] = value;
|
|
@@ -1702,7 +1705,7 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1702
1705
|
})(0);
|
|
1703
1706
|
});
|
|
1704
1707
|
});
|
|
1705
|
-
}
|
|
1708
|
+
}
|
|
1706
1709
|
|
|
1707
1710
|
|
|
1708
1711
|
/**
|
|
@@ -1718,20 +1721,22 @@ promise.map = function(arr, fn, opt_self) {
|
|
|
1718
1721
|
* first failure will be reported; all subsequent errors will be silently
|
|
1719
1722
|
* ignored.
|
|
1720
1723
|
*
|
|
1721
|
-
* @param {!(Array<TYPE>|
|
|
1724
|
+
* @param {!(Array<TYPE>|ManagedPromise<!Array<TYPE>>)} arr The
|
|
1722
1725
|
* array to iterator over, or a promise that will resolve to said array.
|
|
1723
1726
|
* @param {function(this: SELF, TYPE, number, !Array<TYPE>): (
|
|
1724
|
-
* boolean|
|
|
1727
|
+
* boolean|ManagedPromise<boolean>)} fn The function
|
|
1725
1728
|
* to call for each element in the array.
|
|
1726
1729
|
* @param {SELF=} opt_self The object to be used as the value of 'this' within
|
|
1727
1730
|
* {@code fn}.
|
|
1728
1731
|
* @template TYPE, SELF
|
|
1729
1732
|
*/
|
|
1730
|
-
|
|
1731
|
-
return
|
|
1732
|
-
|
|
1733
|
+
function filter(arr, fn, opt_self) {
|
|
1734
|
+
return fulfilled(arr).then(function(v) {
|
|
1735
|
+
if (!Array.isArray(v)) {
|
|
1736
|
+
throw TypeError('not an array');
|
|
1737
|
+
}
|
|
1733
1738
|
var arr = /** @type {!Array} */(v);
|
|
1734
|
-
return new
|
|
1739
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1735
1740
|
var n = arr.length;
|
|
1736
1741
|
var values = [];
|
|
1737
1742
|
var valuesLength = 0;
|
|
@@ -1748,7 +1753,7 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1748
1753
|
try {
|
|
1749
1754
|
var value = arr[i];
|
|
1750
1755
|
var include = fn.call(opt_self, value, i, /** @type {!Array} */(arr));
|
|
1751
|
-
|
|
1756
|
+
asap(include, function(include) {
|
|
1752
1757
|
if (include) {
|
|
1753
1758
|
values[valuesLength++] = value;
|
|
1754
1759
|
}
|
|
@@ -1760,7 +1765,7 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1760
1765
|
})(0);
|
|
1761
1766
|
});
|
|
1762
1767
|
});
|
|
1763
|
-
}
|
|
1768
|
+
}
|
|
1764
1769
|
|
|
1765
1770
|
|
|
1766
1771
|
/**
|
|
@@ -1779,90 +1784,91 @@ promise.filter = function(arr, fn, opt_self) {
|
|
|
1779
1784
|
* promise.fullyResolved(value); // Stack overflow.
|
|
1780
1785
|
*
|
|
1781
1786
|
* @param {*} value The value to fully resolve.
|
|
1782
|
-
* @return {!
|
|
1787
|
+
* @return {!ManagedPromise} A promise for a fully resolved version
|
|
1783
1788
|
* of the input value.
|
|
1784
1789
|
*/
|
|
1785
|
-
|
|
1786
|
-
if (
|
|
1787
|
-
return
|
|
1790
|
+
function fullyResolved(value) {
|
|
1791
|
+
if (isPromise(value)) {
|
|
1792
|
+
return when(value, fullyResolveValue);
|
|
1788
1793
|
}
|
|
1789
1794
|
return fullyResolveValue(value);
|
|
1790
|
-
}
|
|
1795
|
+
}
|
|
1791
1796
|
|
|
1792
1797
|
|
|
1793
1798
|
/**
|
|
1794
1799
|
* @param {*} value The value to fully resolve. If a promise, assumed to
|
|
1795
1800
|
* already be resolved.
|
|
1796
|
-
* @return {!
|
|
1801
|
+
* @return {!ManagedPromise} A promise for a fully resolved version
|
|
1797
1802
|
* of the input value.
|
|
1798
1803
|
*/
|
|
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
|
-
}
|
|
1804
|
+
function fullyResolveValue(value) {
|
|
1805
|
+
if (Array.isArray(value)) {
|
|
1806
|
+
return fullyResolveKeys(/** @type {!Array} */ (value));
|
|
1807
|
+
}
|
|
1813
1808
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1809
|
+
if (isPromise(value)) {
|
|
1810
|
+
if (isPromise(value)) {
|
|
1811
|
+
// We get here when the original input value is a promise that
|
|
1812
|
+
// resolves to itself. When the user provides us with such a promise,
|
|
1813
|
+
// trust that it counts as a "fully resolved" value and return it.
|
|
1814
|
+
// Of course, since it's already a promise, we can just return it
|
|
1815
|
+
// to the user instead of wrapping it in another promise.
|
|
1816
|
+
return /** @type {!ManagedPromise} */ (value);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1821
1819
|
|
|
1822
|
-
|
|
1820
|
+
if (value && typeof value === 'object') {
|
|
1821
|
+
return fullyResolveKeys(/** @type {!Object} */ (value));
|
|
1822
|
+
}
|
|
1823
1823
|
|
|
1824
|
-
|
|
1825
|
-
|
|
1824
|
+
if (typeof value === 'function') {
|
|
1825
|
+
return fullyResolveKeys(/** @type {!Object} */ (value));
|
|
1826
1826
|
}
|
|
1827
|
+
|
|
1828
|
+
return fulfilled(value);
|
|
1827
1829
|
}
|
|
1828
1830
|
|
|
1829
1831
|
|
|
1830
1832
|
/**
|
|
1831
1833
|
* @param {!(Array|Object)} obj the object to resolve.
|
|
1832
|
-
* @return {!
|
|
1834
|
+
* @return {!ManagedPromise} A promise that will be resolved with the
|
|
1833
1835
|
* input object once all of its values have been fully resolved.
|
|
1834
1836
|
*/
|
|
1835
|
-
|
|
1836
|
-
var isArray =
|
|
1837
|
-
var numKeys = isArray ? obj.length :
|
|
1837
|
+
function fullyResolveKeys(obj) {
|
|
1838
|
+
var isArray = Array.isArray(obj);
|
|
1839
|
+
var numKeys = isArray ? obj.length : (function() {
|
|
1840
|
+
let n = 0;
|
|
1841
|
+
for (let key in obj) {
|
|
1842
|
+
n += 1;
|
|
1843
|
+
}
|
|
1844
|
+
return n;
|
|
1845
|
+
})();
|
|
1838
1846
|
if (!numKeys) {
|
|
1839
|
-
return
|
|
1847
|
+
return fulfilled(obj);
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
function forEachProperty(obj, fn) {
|
|
1851
|
+
for (let key in obj) {
|
|
1852
|
+
fn.call(null, obj[key], key, obj);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
function forEachElement(arr, fn) {
|
|
1857
|
+
arr.forEach(fn);
|
|
1840
1858
|
}
|
|
1841
1859
|
|
|
1842
1860
|
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
|
-
};
|
|
1861
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
1862
|
+
var forEachKey = isArray ? forEachElement: forEachProperty;
|
|
1857
1863
|
|
|
1858
1864
|
forEachKey(obj, function(partialValue, key) {
|
|
1859
|
-
|
|
1860
|
-
|
|
1865
|
+
if (!Array.isArray(partialValue)
|
|
1866
|
+
&& (!partialValue || typeof partialValue !== 'object')) {
|
|
1861
1867
|
maybeResolveValue();
|
|
1862
1868
|
return;
|
|
1863
1869
|
}
|
|
1864
1870
|
|
|
1865
|
-
|
|
1871
|
+
fullyResolved(partialValue).then(
|
|
1866
1872
|
function(resolvedValue) {
|
|
1867
1873
|
obj[key] = resolvedValue;
|
|
1868
1874
|
maybeResolveValue();
|
|
@@ -1881,7 +1887,7 @@ promise.fullyResolved = function(value) {
|
|
|
1881
1887
|
|
|
1882
1888
|
//////////////////////////////////////////////////////////////////////////////
|
|
1883
1889
|
//
|
|
1884
|
-
//
|
|
1890
|
+
// ControlFlow
|
|
1885
1891
|
//
|
|
1886
1892
|
//////////////////////////////////////////////////////////////////////////////
|
|
1887
1893
|
|
|
@@ -1893,37 +1899,33 @@ promise.fullyResolved = function(value) {
|
|
|
1893
1899
|
* the ordered scheduled, starting each task only once those before it have
|
|
1894
1900
|
* completed.
|
|
1895
1901
|
*
|
|
1896
|
-
* Each task scheduled within this flow may return a
|
|
1897
|
-
*
|
|
1898
|
-
*
|
|
1899
|
-
* marking the task as completed.
|
|
1902
|
+
* Each task scheduled within this flow may return a {@link ManagedPromise} to
|
|
1903
|
+
* indicate it is an asynchronous operation. The ControlFlow will wait for such
|
|
1904
|
+
* promises to be resolved before marking the task as completed.
|
|
1900
1905
|
*
|
|
1901
|
-
* Tasks and each callback registered on a {@link
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
*
|
|
1906
|
+
* Tasks and each callback registered on a {@link ManagedPromise} will be run
|
|
1907
|
+
* in their own ControlFlow frame. Any tasks scheduled within a frame will take
|
|
1908
|
+
* priority over previously scheduled tasks. Furthermore, if any of the tasks in
|
|
1909
|
+
* the frame fail, the remainder of the tasks in that frame will be discarded
|
|
1910
|
+
* and the failure will be propagated to the user through the callback/task's
|
|
1911
|
+
* promised result.
|
|
1907
1912
|
*
|
|
1908
1913
|
* Each time a ControlFlow empties its task queue, it will fire an
|
|
1909
|
-
* {@link
|
|
1914
|
+
* {@link ControlFlow.EventType.IDLE IDLE} event. Conversely,
|
|
1910
1915
|
* whenever the flow terminates due to an unhandled error, it will remove all
|
|
1911
1916
|
* remaining tasks in its queue and fire an
|
|
1912
|
-
* {@link
|
|
1913
|
-
*
|
|
1914
|
-
*
|
|
1917
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION UNCAUGHT_EXCEPTION} event.
|
|
1918
|
+
* If there are no listeners registered with the flow, the error will be
|
|
1919
|
+
* rethrown to the global error handler.
|
|
1915
1920
|
*
|
|
1916
|
-
* Refer to the {@link
|
|
1921
|
+
* Refer to the {@link ./promise} module documentation fora detailed
|
|
1917
1922
|
* explanation of how the ControlFlow coordinates task execution.
|
|
1918
1923
|
*
|
|
1919
1924
|
* @final
|
|
1920
1925
|
*/
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
/** @constructor */
|
|
1925
|
-
constructor: function() {
|
|
1926
|
-
promise.ControlFlow.base(this, 'constructor');
|
|
1926
|
+
class ControlFlow extends events.EventEmitter {
|
|
1927
|
+
constructor() {
|
|
1928
|
+
super();
|
|
1927
1929
|
|
|
1928
1930
|
/** @private {boolean} */
|
|
1929
1931
|
this.propagateUnhandledRejections_ = true;
|
|
@@ -1937,7 +1939,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1937
1939
|
/**
|
|
1938
1940
|
* Micro task that controls shutting down the control flow. Upon shut down,
|
|
1939
1941
|
* the flow will emit an
|
|
1940
|
-
* {@link
|
|
1942
|
+
* {@link ControlFlow.EventType.IDLE} event. Idle events
|
|
1941
1943
|
* always follow a brief timeout in order to catch latent errors from the
|
|
1942
1944
|
* last completed task. If this task had a callback registered, but no
|
|
1943
1945
|
* errback, and the task fails, the unhandled failure would not be reported
|
|
@@ -1948,7 +1950,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1948
1950
|
* function() { return promise.rejected('failed'); });
|
|
1949
1951
|
* // Set a callback on the result. This delays reporting the unhandled
|
|
1950
1952
|
* // failure for 1 turn of the event loop.
|
|
1951
|
-
* result.then(
|
|
1953
|
+
* result.then(function() {});
|
|
1952
1954
|
*
|
|
1953
1955
|
* @private {MicroTask}
|
|
1954
1956
|
*/
|
|
@@ -1961,28 +1963,27 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1961
1963
|
* _actually_ something to run. When a control flow is waiting on a task,
|
|
1962
1964
|
* there will be nothing in the JS event loop and the process would
|
|
1963
1965
|
* terminate without this.
|
|
1964
|
-
*
|
|
1965
|
-
* @private {?number}
|
|
1966
|
+
* @private
|
|
1966
1967
|
*/
|
|
1967
1968
|
this.hold_ = null;
|
|
1968
|
-
}
|
|
1969
|
+
}
|
|
1969
1970
|
|
|
1970
1971
|
/**
|
|
1971
1972
|
* Returns a string representation of this control flow, which is its current
|
|
1972
|
-
* {@
|
|
1973
|
+
* {@linkplain #getSchedule() schedule}, sans task stack traces.
|
|
1973
1974
|
* @return {string} The string representation of this contorl flow.
|
|
1974
1975
|
* @override
|
|
1975
1976
|
*/
|
|
1976
|
-
toString
|
|
1977
|
+
toString() {
|
|
1977
1978
|
return this.getSchedule();
|
|
1978
|
-
}
|
|
1979
|
+
}
|
|
1979
1980
|
|
|
1980
1981
|
/**
|
|
1981
1982
|
* Sets whether any unhandled rejections should propagate up through the
|
|
1982
1983
|
* control flow stack and cause rejections within parent tasks. If error
|
|
1983
1984
|
* propagation is disabled, tasks will not be aborted when an unhandled
|
|
1984
1985
|
* promise rejection is detected, but the rejection _will_ trigger an
|
|
1985
|
-
* {@link
|
|
1986
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION}
|
|
1986
1987
|
* event.
|
|
1987
1988
|
*
|
|
1988
1989
|
* The default behavior is to propagate all unhandled rejections. _The use
|
|
@@ -1990,26 +1991,26 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
1990
1991
|
*
|
|
1991
1992
|
* @param {boolean} propagate whether to propagate errors.
|
|
1992
1993
|
*/
|
|
1993
|
-
setPropagateUnhandledRejections
|
|
1994
|
+
setPropagateUnhandledRejections(propagate) {
|
|
1994
1995
|
this.propagateUnhandledRejections_ = propagate;
|
|
1995
|
-
}
|
|
1996
|
+
}
|
|
1996
1997
|
|
|
1997
1998
|
/**
|
|
1998
1999
|
* @return {boolean} Whether this flow is currently idle.
|
|
1999
2000
|
*/
|
|
2000
|
-
isIdle
|
|
2001
|
+
isIdle() {
|
|
2001
2002
|
return !this.shutdownTask_ && (!this.taskQueues_ || !this.taskQueues_.size);
|
|
2002
|
-
}
|
|
2003
|
+
}
|
|
2003
2004
|
|
|
2004
2005
|
/**
|
|
2005
2006
|
* Resets this instance, clearing its queue and removing all event listeners.
|
|
2006
2007
|
*/
|
|
2007
|
-
reset
|
|
2008
|
+
reset() {
|
|
2008
2009
|
this.cancelQueues_(new FlowResetError);
|
|
2009
|
-
this.emit(
|
|
2010
|
+
this.emit(ControlFlow.EventType.RESET);
|
|
2010
2011
|
this.removeAllListeners();
|
|
2011
2012
|
this.cancelShutdown_();
|
|
2012
|
-
}
|
|
2013
|
+
}
|
|
2013
2014
|
|
|
2014
2015
|
/**
|
|
2015
2016
|
* Generates an annotated string describing the internal state of this control
|
|
@@ -2020,8 +2021,8 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2020
2021
|
* from when each task was scheduled. Defaults to false.
|
|
2021
2022
|
* @return {string} String representation of this flow's internal state.
|
|
2022
2023
|
*/
|
|
2023
|
-
getSchedule
|
|
2024
|
-
var ret = 'ControlFlow::' +
|
|
2024
|
+
getSchedule(opt_includeStackTraces) {
|
|
2025
|
+
var ret = 'ControlFlow::' + getUid(this);
|
|
2025
2026
|
var activeQueue = this.activeQueue_;
|
|
2026
2027
|
if (!this.taskQueues_ || !this.taskQueues_.size) {
|
|
2027
2028
|
return ret;
|
|
@@ -2066,7 +2067,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2066
2067
|
}
|
|
2067
2068
|
return ret;
|
|
2068
2069
|
}
|
|
2069
|
-
}
|
|
2070
|
+
}
|
|
2070
2071
|
|
|
2071
2072
|
/**
|
|
2072
2073
|
* Returns the currently actively task queue for this flow. If there is no
|
|
@@ -2074,7 +2075,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2074
2075
|
* @return {!TaskQueue} the currently active task queue for this flow.
|
|
2075
2076
|
* @private
|
|
2076
2077
|
*/
|
|
2077
|
-
getActiveQueue_
|
|
2078
|
+
getActiveQueue_() {
|
|
2078
2079
|
if (this.activeQueue_) {
|
|
2079
2080
|
return this.activeQueue_;
|
|
2080
2081
|
}
|
|
@@ -2088,45 +2089,46 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2088
2089
|
.once('end', this.onQueueEnd_, this)
|
|
2089
2090
|
.once('error', this.onQueueError_, this);
|
|
2090
2091
|
|
|
2091
|
-
asyncRun(() => this.activeQueue_ = null
|
|
2092
|
+
asyncRun(() => this.activeQueue_ = null);
|
|
2092
2093
|
this.activeQueue_.start();
|
|
2093
2094
|
return this.activeQueue_;
|
|
2094
|
-
}
|
|
2095
|
+
}
|
|
2095
2096
|
|
|
2096
2097
|
/**
|
|
2097
2098
|
* Schedules a task for execution. If there is nothing currently in the
|
|
2098
2099
|
* queue, the task will be executed in the next turn of the event loop. If
|
|
2099
2100
|
* the task function is a generator, the task will be executed using
|
|
2100
|
-
* {@link
|
|
2101
|
+
* {@link ./promise.consume consume()}.
|
|
2101
2102
|
*
|
|
2102
|
-
* @param {function(): (T|
|
|
2103
|
+
* @param {function(): (T|ManagedPromise<T>)} fn The function to
|
|
2103
2104
|
* call to start the task. If the function returns a
|
|
2104
|
-
* {@link
|
|
2105
|
+
* {@link ManagedPromise}, this instance will wait for it to be
|
|
2105
2106
|
* resolved before starting the next task.
|
|
2106
2107
|
* @param {string=} opt_description A description of the task.
|
|
2107
|
-
* @return {!
|
|
2108
|
+
* @return {!ManagedPromise<T>} A promise that will be resolved
|
|
2108
2109
|
* with the result of the action.
|
|
2109
2110
|
* @template T
|
|
2110
2111
|
*/
|
|
2111
|
-
execute
|
|
2112
|
-
if (
|
|
2113
|
-
|
|
2112
|
+
execute(fn, opt_description) {
|
|
2113
|
+
if (isGenerator(fn)) {
|
|
2114
|
+
let original = fn;
|
|
2115
|
+
fn = () => consume(original);
|
|
2114
2116
|
}
|
|
2115
2117
|
|
|
2116
2118
|
if (!this.hold_) {
|
|
2117
2119
|
var holdIntervalMs = 2147483647; // 2^31-1; max timer length for Node.js
|
|
2118
|
-
this.hold_ = setInterval(
|
|
2120
|
+
this.hold_ = setInterval(function() {}, holdIntervalMs);
|
|
2119
2121
|
}
|
|
2120
2122
|
|
|
2121
2123
|
var task = new Task(
|
|
2122
2124
|
this, fn, opt_description || '<anonymous>',
|
|
2123
|
-
{name: 'Task', top:
|
|
2125
|
+
{name: 'Task', top: ControlFlow.prototype.execute});
|
|
2124
2126
|
|
|
2125
2127
|
var q = this.getActiveQueue_();
|
|
2126
2128
|
q.enqueue(task);
|
|
2127
|
-
this.emit(
|
|
2129
|
+
this.emit(ControlFlow.EventType.SCHEDULE_TASK, task.description);
|
|
2128
2130
|
return task.promise;
|
|
2129
|
-
}
|
|
2131
|
+
}
|
|
2130
2132
|
|
|
2131
2133
|
/**
|
|
2132
2134
|
* Inserts a {@code setTimeout} into the command queue. This is equivalent to
|
|
@@ -2134,14 +2136,14 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2134
2136
|
*
|
|
2135
2137
|
* @param {number} ms The timeout delay, in milliseconds.
|
|
2136
2138
|
* @param {string=} opt_description A description to accompany the timeout.
|
|
2137
|
-
* @return {!
|
|
2139
|
+
* @return {!ManagedPromise} A promise that will be resolved with
|
|
2138
2140
|
* the result of the action.
|
|
2139
2141
|
*/
|
|
2140
|
-
timeout
|
|
2142
|
+
timeout(ms, opt_description) {
|
|
2141
2143
|
return this.execute(function() {
|
|
2142
|
-
return
|
|
2144
|
+
return delayed(ms);
|
|
2143
2145
|
}, opt_description);
|
|
2144
|
-
}
|
|
2146
|
+
}
|
|
2145
2147
|
|
|
2146
2148
|
/**
|
|
2147
2149
|
* Schedules a task that shall wait for a condition to hold. Each condition
|
|
@@ -2151,7 +2153,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2151
2153
|
* Condition functions may schedule sub-tasks with this instance, however,
|
|
2152
2154
|
* their execution time will be factored into whether a wait has timed out.
|
|
2153
2155
|
*
|
|
2154
|
-
* In the event a condition returns a
|
|
2156
|
+
* In the event a condition returns a ManagedPromise, the polling loop will wait for
|
|
2155
2157
|
* it to be resolved before evaluating whether the condition has been
|
|
2156
2158
|
* satisfied. The resolution time for a promise is factored into whether a
|
|
2157
2159
|
* wait has timed out.
|
|
@@ -2166,38 +2168,38 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2166
2168
|
* If this function is invoked with `timeout === 0`, or the timeout is
|
|
2167
2169
|
* omitted, the flow will wait indefinitely for the condition to be satisfied.
|
|
2168
2170
|
*
|
|
2169
|
-
* @param {(!
|
|
2171
|
+
* @param {(!ManagedPromise<T>|function())} condition The condition to poll,
|
|
2170
2172
|
* or a promise to wait on.
|
|
2171
2173
|
* @param {number=} opt_timeout How long to wait, in milliseconds, for the
|
|
2172
2174
|
* condition to hold before timing out. If omitted, the flow will wait
|
|
2173
2175
|
* indefinitely.
|
|
2174
2176
|
* @param {string=} opt_message An optional error message to include if the
|
|
2175
2177
|
* wait times out; defaults to the empty string.
|
|
2176
|
-
* @return {!
|
|
2178
|
+
* @return {!ManagedPromise<T>} A promise that will be fulfilled
|
|
2177
2179
|
* when the condition has been satisified. The promise shall be rejected
|
|
2178
2180
|
* if the wait times out waiting for the condition.
|
|
2179
2181
|
* @throws {TypeError} If condition is not a function or promise or if timeout
|
|
2180
2182
|
* is not a number >= 0.
|
|
2181
2183
|
* @template T
|
|
2182
2184
|
*/
|
|
2183
|
-
wait
|
|
2185
|
+
wait(condition, opt_timeout, opt_message) {
|
|
2184
2186
|
var timeout = opt_timeout || 0;
|
|
2185
|
-
if (
|
|
2187
|
+
if (typeof timeout !== 'number' || timeout < 0) {
|
|
2186
2188
|
throw TypeError('timeout must be a number >= 0: ' + timeout);
|
|
2187
2189
|
}
|
|
2188
2190
|
|
|
2189
|
-
if (
|
|
2191
|
+
if (isPromise(condition)) {
|
|
2190
2192
|
return this.execute(function() {
|
|
2191
2193
|
if (!timeout) {
|
|
2192
2194
|
return condition;
|
|
2193
2195
|
}
|
|
2194
|
-
return new
|
|
2195
|
-
var start =
|
|
2196
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
2197
|
+
var start = Date.now();
|
|
2196
2198
|
var timer = setTimeout(function() {
|
|
2197
2199
|
timer = null;
|
|
2198
2200
|
reject(Error((opt_message ? opt_message + '\n' : '') +
|
|
2199
2201
|
'Timed out waiting for promise to resolve after ' +
|
|
2200
|
-
(
|
|
2202
|
+
(Date.now() - start) + 'ms'));
|
|
2201
2203
|
}, timeout);
|
|
2202
2204
|
|
|
2203
2205
|
/** @type {Thenable} */(condition).then(
|
|
@@ -2213,25 +2215,26 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2213
2215
|
}, opt_message || '<anonymous wait: promise resolution>');
|
|
2214
2216
|
}
|
|
2215
2217
|
|
|
2216
|
-
if (
|
|
2218
|
+
if (typeof condition !== 'function') {
|
|
2217
2219
|
throw TypeError('Invalid condition; must be a function or promise: ' +
|
|
2218
|
-
|
|
2220
|
+
typeof condition);
|
|
2219
2221
|
}
|
|
2220
2222
|
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
2223
|
+
if (isGenerator(condition)) {
|
|
2224
|
+
let original = condition;
|
|
2225
|
+
condition = () => consume(original);
|
|
2223
2226
|
}
|
|
2224
2227
|
|
|
2225
2228
|
var self = this;
|
|
2226
2229
|
return this.execute(function() {
|
|
2227
|
-
var startTime =
|
|
2228
|
-
return new
|
|
2230
|
+
var startTime = Date.now();
|
|
2231
|
+
return new ManagedPromise(function(fulfill, reject) {
|
|
2229
2232
|
pollCondition();
|
|
2230
2233
|
|
|
2231
2234
|
function pollCondition() {
|
|
2232
2235
|
var conditionFn = /** @type {function()} */(condition);
|
|
2233
2236
|
self.execute(conditionFn).then(function(value) {
|
|
2234
|
-
var elapsed =
|
|
2237
|
+
var elapsed = Date.now() - startTime;
|
|
2235
2238
|
if (!!value) {
|
|
2236
2239
|
fulfill(value);
|
|
2237
2240
|
} else if (timeout && elapsed >= timeout) {
|
|
@@ -2247,7 +2250,7 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2247
2250
|
}
|
|
2248
2251
|
});
|
|
2249
2252
|
}, opt_message || '<anonymous wait>');
|
|
2250
|
-
}
|
|
2253
|
+
}
|
|
2251
2254
|
|
|
2252
2255
|
/**
|
|
2253
2256
|
* Executes a function in the next available turn of the JavaScript event
|
|
@@ -2285,36 +2288,36 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2285
2288
|
* @param {Object=} opt_self The object in whose context to run the function.
|
|
2286
2289
|
* @param {...*} var_args Any arguments to pass to the function.
|
|
2287
2290
|
*/
|
|
2288
|
-
async
|
|
2289
|
-
asyncRun(
|
|
2291
|
+
async(fn, opt_self, var_args) {
|
|
2292
|
+
asyncRun(() => {
|
|
2290
2293
|
// Clear any lingering queues, forces getActiveQueue_ to create a new one.
|
|
2291
2294
|
this.activeQueue_ = null;
|
|
2292
2295
|
var q = this.getActiveQueue_();
|
|
2293
2296
|
try {
|
|
2294
2297
|
q.execute_(fn.bind(opt_self, var_args));
|
|
2295
2298
|
} catch (ex) {
|
|
2296
|
-
var cancellationError =
|
|
2299
|
+
var cancellationError = CancellationError.wrap(ex,
|
|
2297
2300
|
'Function passed to ControlFlow.async() threw');
|
|
2298
2301
|
cancellationError.silent_ = true;
|
|
2299
2302
|
q.abort_(cancellationError);
|
|
2300
2303
|
} finally {
|
|
2301
2304
|
this.activeQueue_ = null;
|
|
2302
2305
|
}
|
|
2303
|
-
}
|
|
2304
|
-
}
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2305
2308
|
|
|
2306
2309
|
/**
|
|
2307
2310
|
* Event handler for when a task queue is exhausted. This starts the shutdown
|
|
2308
2311
|
* sequence for this instance if there are no remaining task queues: after
|
|
2309
2312
|
* one turn of the event loop, this object will emit the
|
|
2310
|
-
* {@link
|
|
2313
|
+
* {@link ControlFlow.EventType.IDLE IDLE} event to signal
|
|
2311
2314
|
* listeners that it has completed. During this wait, if another task is
|
|
2312
2315
|
* scheduled, the shutdown will be aborted.
|
|
2313
2316
|
*
|
|
2314
2317
|
* @param {!TaskQueue} q the completed task queue.
|
|
2315
2318
|
* @private
|
|
2316
2319
|
*/
|
|
2317
|
-
onQueueEnd_
|
|
2320
|
+
onQueueEnd_(q) {
|
|
2318
2321
|
if (!this.taskQueues_) {
|
|
2319
2322
|
return;
|
|
2320
2323
|
}
|
|
@@ -2324,15 +2327,18 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2324
2327
|
vlog(1, () => this.taskQueues_.size + ' queues remain\n' + this, this);
|
|
2325
2328
|
|
|
2326
2329
|
if (!this.taskQueues_.size) {
|
|
2327
|
-
|
|
2328
|
-
|
|
2330
|
+
if (this.shutdownTask_) {
|
|
2331
|
+
throw Error('Already have a shutdown task??');
|
|
2332
|
+
}
|
|
2333
|
+
vlog(1, () => 'Scheduling shutdown\n' + this);
|
|
2334
|
+
this.shutdownTask_ = new MicroTask(() => this.shutdown_());
|
|
2329
2335
|
}
|
|
2330
|
-
}
|
|
2336
|
+
}
|
|
2331
2337
|
|
|
2332
2338
|
/**
|
|
2333
2339
|
* Event handler for when a task queue terminates with an error. This triggers
|
|
2334
2340
|
* the cancellation of all other task queues and a
|
|
2335
|
-
* {@link
|
|
2341
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
|
|
2336
2342
|
* If there are no error event listeners registered with this instance, the
|
|
2337
2343
|
* error will be rethrown to the global error handler.
|
|
2338
2344
|
*
|
|
@@ -2340,30 +2346,30 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2340
2346
|
* @param {!TaskQueue} q the task queue.
|
|
2341
2347
|
* @private
|
|
2342
2348
|
*/
|
|
2343
|
-
onQueueError_
|
|
2349
|
+
onQueueError_(error, q) {
|
|
2344
2350
|
if (this.taskQueues_) {
|
|
2345
2351
|
this.taskQueues_.delete(q);
|
|
2346
2352
|
}
|
|
2347
|
-
this.cancelQueues_(
|
|
2353
|
+
this.cancelQueues_(CancellationError.wrap(
|
|
2348
2354
|
error, 'There was an uncaught error in the control flow'));
|
|
2349
2355
|
this.cancelShutdown_();
|
|
2350
2356
|
this.cancelHold_();
|
|
2351
2357
|
|
|
2352
2358
|
var listeners = this.listeners(
|
|
2353
|
-
|
|
2354
|
-
if (!listeners.
|
|
2355
|
-
|
|
2359
|
+
ControlFlow.EventType.UNCAUGHT_EXCEPTION);
|
|
2360
|
+
if (!listeners.size) {
|
|
2361
|
+
asyncThrow(/** @type {!Error} */(error));
|
|
2356
2362
|
} else {
|
|
2357
2363
|
this.reportUncaughtException_(error);
|
|
2358
2364
|
}
|
|
2359
|
-
}
|
|
2365
|
+
}
|
|
2360
2366
|
|
|
2361
2367
|
/**
|
|
2362
2368
|
* Cancels all remaining task queues.
|
|
2363
|
-
* @param {!
|
|
2369
|
+
* @param {!CancellationError} reason The cancellation reason.
|
|
2364
2370
|
* @private
|
|
2365
2371
|
*/
|
|
2366
|
-
cancelQueues_
|
|
2372
|
+
cancelQueues_(reason) {
|
|
2367
2373
|
reason.silent_ = true;
|
|
2368
2374
|
if (this.taskQueues_) {
|
|
2369
2375
|
for (var q of this.taskQueues_) {
|
|
@@ -2373,53 +2379,53 @@ promise.ControlFlow = goog.defineClass(EventEmitter, {
|
|
|
2373
2379
|
this.taskQueues_.clear();
|
|
2374
2380
|
this.taskQueues_ = null;
|
|
2375
2381
|
}
|
|
2376
|
-
}
|
|
2382
|
+
}
|
|
2377
2383
|
|
|
2378
2384
|
/**
|
|
2379
2385
|
* Reports an uncaught exception using a
|
|
2380
|
-
* {@link
|
|
2386
|
+
* {@link ControlFlow.EventType.UNCAUGHT_EXCEPTION} event.
|
|
2381
2387
|
*
|
|
2382
2388
|
* @param {*} e the error to report.
|
|
2383
2389
|
* @private
|
|
2384
2390
|
*/
|
|
2385
|
-
reportUncaughtException_
|
|
2386
|
-
this.emit(
|
|
2387
|
-
}
|
|
2391
|
+
reportUncaughtException_(e) {
|
|
2392
|
+
this.emit(ControlFlow.EventType.UNCAUGHT_EXCEPTION, e);
|
|
2393
|
+
}
|
|
2388
2394
|
|
|
2389
2395
|
/** @private */
|
|
2390
|
-
cancelHold_
|
|
2396
|
+
cancelHold_() {
|
|
2391
2397
|
if (this.hold_) {
|
|
2392
2398
|
clearInterval(this.hold_);
|
|
2393
2399
|
this.hold_ = null;
|
|
2394
2400
|
}
|
|
2395
|
-
}
|
|
2401
|
+
}
|
|
2396
2402
|
|
|
2397
2403
|
/** @private */
|
|
2398
|
-
shutdown_
|
|
2404
|
+
shutdown_() {
|
|
2399
2405
|
vlog(1, () => 'Going idle: ' + this);
|
|
2400
2406
|
this.cancelHold_();
|
|
2401
2407
|
this.shutdownTask_ = null;
|
|
2402
|
-
this.emit(
|
|
2403
|
-
}
|
|
2408
|
+
this.emit(ControlFlow.EventType.IDLE);
|
|
2409
|
+
}
|
|
2404
2410
|
|
|
2405
2411
|
/**
|
|
2406
2412
|
* Cancels the shutdown sequence if it is currently scheduled.
|
|
2407
2413
|
* @private
|
|
2408
2414
|
*/
|
|
2409
|
-
cancelShutdown_
|
|
2415
|
+
cancelShutdown_() {
|
|
2410
2416
|
if (this.shutdownTask_) {
|
|
2411
2417
|
this.shutdownTask_.cancel();
|
|
2412
2418
|
this.shutdownTask_ = null;
|
|
2413
2419
|
}
|
|
2414
2420
|
}
|
|
2415
|
-
}
|
|
2421
|
+
}
|
|
2416
2422
|
|
|
2417
2423
|
|
|
2418
2424
|
/**
|
|
2419
|
-
* Events that may be emitted by an {@link
|
|
2425
|
+
* Events that may be emitted by an {@link ControlFlow}.
|
|
2420
2426
|
* @enum {string}
|
|
2421
2427
|
*/
|
|
2422
|
-
|
|
2428
|
+
ControlFlow.EventType = {
|
|
2423
2429
|
|
|
2424
2430
|
/** Emitted when all tasks have been successfully executed. */
|
|
2425
2431
|
IDLE: 'idle',
|
|
@@ -2444,56 +2450,67 @@ promise.ControlFlow.EventType = {
|
|
|
2444
2450
|
* Wraps a function to execute as a cancellable micro task.
|
|
2445
2451
|
* @final
|
|
2446
2452
|
*/
|
|
2447
|
-
|
|
2453
|
+
class MicroTask {
|
|
2448
2454
|
/**
|
|
2449
|
-
* @param {function(
|
|
2450
|
-
* @param {THIS=} opt_scope The scope to run the function in.
|
|
2451
|
-
* @template THIS
|
|
2455
|
+
* @param {function()} fn The function to run as a micro task.
|
|
2452
2456
|
*/
|
|
2453
|
-
constructor
|
|
2457
|
+
constructor(fn) {
|
|
2454
2458
|
/** @private {boolean} */
|
|
2455
2459
|
this.cancelled_ = false;
|
|
2456
|
-
asyncRun(
|
|
2460
|
+
asyncRun(() => {
|
|
2457
2461
|
if (!this.cancelled_) {
|
|
2458
|
-
fn
|
|
2462
|
+
fn();
|
|
2459
2463
|
}
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
/**
|
|
2468
|
+
* Runs the given function after a micro-task yield.
|
|
2469
|
+
* @param {function()} fn The function to run.
|
|
2470
|
+
*/
|
|
2471
|
+
static run(fn) {
|
|
2472
|
+
NativePromise.resolve().then(function() {
|
|
2473
|
+
try {
|
|
2474
|
+
fn();
|
|
2475
|
+
} catch (ignored) {
|
|
2476
|
+
// Do nothing.
|
|
2477
|
+
}
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2462
2480
|
|
|
2463
2481
|
/**
|
|
2464
2482
|
* Cancels the execution of this task. Note: this will not prevent the task
|
|
2465
2483
|
* timer from firing, just the invocation of the wrapped function.
|
|
2466
2484
|
*/
|
|
2467
|
-
cancel
|
|
2485
|
+
cancel() {
|
|
2468
2486
|
this.cancelled_ = true;
|
|
2469
2487
|
}
|
|
2470
|
-
}
|
|
2488
|
+
}
|
|
2471
2489
|
|
|
2472
2490
|
|
|
2473
2491
|
/**
|
|
2474
|
-
* A task to be executed by a {@link
|
|
2492
|
+
* A task to be executed by a {@link ControlFlow}.
|
|
2475
2493
|
*
|
|
2494
|
+
* @template T
|
|
2476
2495
|
* @final
|
|
2477
2496
|
*/
|
|
2478
|
-
|
|
2497
|
+
class Task extends Deferred {
|
|
2479
2498
|
/**
|
|
2480
|
-
* @param {!
|
|
2499
|
+
* @param {!ControlFlow} flow The flow this instances belongs
|
|
2481
2500
|
* to.
|
|
2482
|
-
* @param {function(): (T|!
|
|
2501
|
+
* @param {function(): (T|!ManagedPromise<T>)} fn The function to
|
|
2483
2502
|
* call when the task executes. If it returns a
|
|
2484
|
-
* {@link
|
|
2503
|
+
* {@link ManagedPromise}, the flow will wait for it to be
|
|
2485
2504
|
* resolved before starting the next task.
|
|
2486
2505
|
* @param {string} description A description of the task for debugging.
|
|
2487
2506
|
* @param {{name: string, top: !Function}=} opt_stackOptions Options to use
|
|
2488
2507
|
* when capturing the stacktrace for when this task was created.
|
|
2489
|
-
* @constructor
|
|
2490
|
-
* @extends {promise.Deferred<T>}
|
|
2491
|
-
* @template T
|
|
2492
2508
|
*/
|
|
2493
|
-
constructor
|
|
2494
|
-
|
|
2509
|
+
constructor(flow, fn, description, opt_stackOptions) {
|
|
2510
|
+
super(flow);
|
|
2511
|
+
getUid(this);
|
|
2495
2512
|
|
|
2496
|
-
/** @type {function(): (T|!
|
|
2513
|
+
/** @type {function(): (T|!ManagedPromise<T>)} */
|
|
2497
2514
|
this.execute = fn;
|
|
2498
2515
|
|
|
2499
2516
|
/** @type {string} */
|
|
@@ -2519,20 +2536,20 @@ var Task = goog.defineClass(promise.Deferred, {
|
|
|
2519
2536
|
this.blocked = false;
|
|
2520
2537
|
|
|
2521
2538
|
if (opt_stackOptions) {
|
|
2522
|
-
this.promise.stack_ =
|
|
2539
|
+
this.promise.stack_ = captureStackTrace(
|
|
2523
2540
|
opt_stackOptions.name, this.description, opt_stackOptions.top);
|
|
2524
2541
|
}
|
|
2525
|
-
}
|
|
2542
|
+
}
|
|
2526
2543
|
|
|
2527
2544
|
/** @override */
|
|
2528
|
-
toString
|
|
2529
|
-
return 'Task::' +
|
|
2545
|
+
toString() {
|
|
2546
|
+
return 'Task::' + getUid(this) + '<' + this.description + '>';
|
|
2530
2547
|
}
|
|
2531
|
-
}
|
|
2548
|
+
}
|
|
2532
2549
|
|
|
2533
2550
|
|
|
2534
2551
|
/** @enum {string} */
|
|
2535
|
-
|
|
2552
|
+
const TaskQueueState = {
|
|
2536
2553
|
NEW: 'new',
|
|
2537
2554
|
STARTED: 'started',
|
|
2538
2555
|
FINISHED: 'finished'
|
|
@@ -2542,16 +2559,15 @@ var TaskQueueState = {
|
|
|
2542
2559
|
/**
|
|
2543
2560
|
* @final
|
|
2544
2561
|
*/
|
|
2545
|
-
|
|
2546
|
-
/** @param {!
|
|
2547
|
-
constructor
|
|
2548
|
-
|
|
2549
|
-
goog.getUid(this);
|
|
2562
|
+
class TaskQueue extends events.EventEmitter {
|
|
2563
|
+
/** @param {!ControlFlow} flow . */
|
|
2564
|
+
constructor(flow) {
|
|
2565
|
+
super();
|
|
2550
2566
|
|
|
2551
2567
|
/** @private {string} */
|
|
2552
|
-
this.name_ = 'TaskQueue::' +
|
|
2568
|
+
this.name_ = 'TaskQueue::' + getUid(this);
|
|
2553
2569
|
|
|
2554
|
-
/** @private {!
|
|
2570
|
+
/** @private {!ControlFlow} */
|
|
2555
2571
|
this.flow_ = flow;
|
|
2556
2572
|
|
|
2557
2573
|
/** @private {!Array<!Task>} */
|
|
@@ -2566,41 +2582,41 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2566
2582
|
/** @private {TaskQueueState} */
|
|
2567
2583
|
this.state_ = TaskQueueState.NEW;
|
|
2568
2584
|
|
|
2569
|
-
/** @private {!Set<!
|
|
2585
|
+
/** @private {!Set<!ManagedPromise>} */
|
|
2570
2586
|
this.unhandledRejections_ = new Set();
|
|
2571
|
-
}
|
|
2587
|
+
}
|
|
2572
2588
|
|
|
2573
2589
|
/** @override */
|
|
2574
|
-
toString
|
|
2575
|
-
return 'TaskQueue::' +
|
|
2576
|
-
}
|
|
2590
|
+
toString() {
|
|
2591
|
+
return 'TaskQueue::' + getUid(this);
|
|
2592
|
+
}
|
|
2577
2593
|
|
|
2578
2594
|
/**
|
|
2579
|
-
* @param {!
|
|
2595
|
+
* @param {!ManagedPromise} promise .
|
|
2580
2596
|
*/
|
|
2581
|
-
addUnhandledRejection
|
|
2597
|
+
addUnhandledRejection(promise) {
|
|
2582
2598
|
// TODO: node 4.0.0+
|
|
2583
2599
|
vlog(2, () => this + ' registering unhandled rejection: ' + promise, this);
|
|
2584
2600
|
this.unhandledRejections_.add(promise);
|
|
2585
|
-
}
|
|
2601
|
+
}
|
|
2586
2602
|
|
|
2587
2603
|
/**
|
|
2588
|
-
* @param {!
|
|
2604
|
+
* @param {!ManagedPromise} promise .
|
|
2589
2605
|
*/
|
|
2590
|
-
clearUnhandledRejection
|
|
2606
|
+
clearUnhandledRejection(promise) {
|
|
2591
2607
|
var deleted = this.unhandledRejections_.delete(promise);
|
|
2592
2608
|
if (deleted) {
|
|
2593
2609
|
// TODO: node 4.0.0+
|
|
2594
2610
|
vlog(2, () => this + ' clearing unhandled rejection: ' + promise, this);
|
|
2595
2611
|
}
|
|
2596
|
-
}
|
|
2612
|
+
}
|
|
2597
2613
|
|
|
2598
2614
|
/**
|
|
2599
2615
|
* Enqueues a new task for execution.
|
|
2600
2616
|
* @param {!Task} task The task to enqueue.
|
|
2601
2617
|
* @throws {Error} If this instance has already started execution.
|
|
2602
2618
|
*/
|
|
2603
|
-
enqueue
|
|
2619
|
+
enqueue(task) {
|
|
2604
2620
|
if (this.state_ !== TaskQueueState.NEW) {
|
|
2605
2621
|
throw Error('TaskQueue has started: ' + this);
|
|
2606
2622
|
}
|
|
@@ -2616,16 +2632,16 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2616
2632
|
|
|
2617
2633
|
vlog(1, () => this + '.enqueue(' + task + ')', this);
|
|
2618
2634
|
vlog(2, () => this.flow_.toString(), this);
|
|
2619
|
-
}
|
|
2635
|
+
}
|
|
2620
2636
|
|
|
2621
2637
|
/**
|
|
2622
2638
|
* Schedules the callbacks registered on the given promise in this queue.
|
|
2623
2639
|
*
|
|
2624
|
-
* @param {!
|
|
2640
|
+
* @param {!ManagedPromise} promise the promise whose callbacks should be
|
|
2625
2641
|
* registered as interrupts in this task queue.
|
|
2626
2642
|
* @throws {Error} if this queue has already finished.
|
|
2627
2643
|
*/
|
|
2628
|
-
scheduleCallbacks
|
|
2644
|
+
scheduleCallbacks(promise) {
|
|
2629
2645
|
if (this.state_ === TaskQueueState.FINISHED) {
|
|
2630
2646
|
throw new Error('cannot interrupt a finished q(' + this + ')');
|
|
2631
2647
|
}
|
|
@@ -2633,7 +2649,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2633
2649
|
if (this.pending_ && this.pending_.task.promise === promise) {
|
|
2634
2650
|
this.pending_.task.promise.queue_ = null;
|
|
2635
2651
|
this.pending_ = null;
|
|
2636
|
-
asyncRun(this.executeNext_
|
|
2652
|
+
asyncRun(() => this.executeNext_());
|
|
2637
2653
|
}
|
|
2638
2654
|
|
|
2639
2655
|
if (!promise.callbacks_) {
|
|
@@ -2663,7 +2679,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2663
2679
|
}, this);
|
|
2664
2680
|
promise.callbacks_ = null;
|
|
2665
2681
|
vlog(2, () => this + ' interrupted\n' + this.flow_, this);
|
|
2666
|
-
}
|
|
2682
|
+
}
|
|
2667
2683
|
|
|
2668
2684
|
/**
|
|
2669
2685
|
* Starts executing tasks in this queue. Once called, no further tasks may
|
|
@@ -2671,15 +2687,15 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2671
2687
|
*
|
|
2672
2688
|
* @throws {Error} if this queue has already been started.
|
|
2673
2689
|
*/
|
|
2674
|
-
start
|
|
2690
|
+
start() {
|
|
2675
2691
|
if (this.state_ !== TaskQueueState.NEW) {
|
|
2676
2692
|
throw new Error('TaskQueue has already started');
|
|
2677
2693
|
}
|
|
2678
2694
|
// Always asynchronously execute next, even if there doesn't look like
|
|
2679
2695
|
// there is anything in the queue. This will catch pending unhandled
|
|
2680
2696
|
// rejections that were registered before start was called.
|
|
2681
|
-
asyncRun(this.executeNext_
|
|
2682
|
-
}
|
|
2697
|
+
asyncRun(() => this.executeNext_());
|
|
2698
|
+
}
|
|
2683
2699
|
|
|
2684
2700
|
/**
|
|
2685
2701
|
* Aborts this task queue. If there are any scheduled tasks, they are silently
|
|
@@ -2690,7 +2706,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2690
2706
|
* @param {*} error The abortion reason.
|
|
2691
2707
|
* @private
|
|
2692
2708
|
*/
|
|
2693
|
-
abort_
|
|
2709
|
+
abort_(error) {
|
|
2694
2710
|
var cancellation;
|
|
2695
2711
|
|
|
2696
2712
|
if (error instanceof FlowResetError) {
|
|
@@ -2711,17 +2727,16 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2711
2727
|
|
|
2712
2728
|
if (this.pending_) {
|
|
2713
2729
|
vlog(2, () => this + '.abort(); cancelling pending task', this);
|
|
2714
|
-
this.pending_.task.cancel(
|
|
2715
|
-
/** @type {!webdriver.promise.CancellationError} */(error));
|
|
2730
|
+
this.pending_.task.cancel(/** @type {!CancellationError} */(error));
|
|
2716
2731
|
|
|
2717
2732
|
} else {
|
|
2718
2733
|
vlog(2, () => this + '.abort(); emitting error event', this);
|
|
2719
2734
|
this.emit('error', error, this);
|
|
2720
2735
|
}
|
|
2721
|
-
}
|
|
2736
|
+
}
|
|
2722
2737
|
|
|
2723
2738
|
/** @private */
|
|
2724
|
-
executeNext_
|
|
2739
|
+
executeNext_() {
|
|
2725
2740
|
if (this.state_ === TaskQueueState.FINISHED) {
|
|
2726
2741
|
return;
|
|
2727
2742
|
}
|
|
@@ -2760,8 +2775,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2760
2775
|
} catch (ex) {
|
|
2761
2776
|
subQ.abort_(ex);
|
|
2762
2777
|
}
|
|
2763
|
-
}
|
|
2764
|
-
|
|
2778
|
+
}
|
|
2765
2779
|
|
|
2766
2780
|
/**
|
|
2767
2781
|
* @param {!Function} fn .
|
|
@@ -2769,7 +2783,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2769
2783
|
* @template T
|
|
2770
2784
|
* @private
|
|
2771
2785
|
*/
|
|
2772
|
-
execute_
|
|
2786
|
+
execute_(fn) {
|
|
2773
2787
|
try {
|
|
2774
2788
|
activeFlows.push(this.flow_);
|
|
2775
2789
|
this.flow_.activeQueue_ = this;
|
|
@@ -2778,17 +2792,17 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2778
2792
|
this.flow_.activeQueue_ = null;
|
|
2779
2793
|
activeFlows.pop();
|
|
2780
2794
|
}
|
|
2781
|
-
}
|
|
2795
|
+
}
|
|
2782
2796
|
|
|
2783
2797
|
/**
|
|
2784
2798
|
* Process any unhandled rejections registered with this task queue. If there
|
|
2785
2799
|
* is a rejection, this queue will be aborted with the rejection error. If
|
|
2786
2800
|
* there are multiple rejections registered, this queue will be aborted with
|
|
2787
|
-
* a {@link
|
|
2801
|
+
* a {@link MultipleUnhandledRejectionError}.
|
|
2788
2802
|
* @return {boolean} whether there was an unhandled rejection.
|
|
2789
2803
|
* @private
|
|
2790
2804
|
*/
|
|
2791
|
-
processUnhandledRejections_
|
|
2805
|
+
processUnhandledRejections_() {
|
|
2792
2806
|
if (!this.unhandledRejections_.size) {
|
|
2793
2807
|
return false;
|
|
2794
2808
|
}
|
|
@@ -2801,7 +2815,7 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2801
2815
|
|
|
2802
2816
|
var errorToReport = errors.size === 1
|
|
2803
2817
|
? errors.values().next().value
|
|
2804
|
-
: new
|
|
2818
|
+
: new MultipleUnhandledRejectionError(errors);
|
|
2805
2819
|
|
|
2806
2820
|
vlog(1, () => this + ' aborting due to unhandled rejections', this);
|
|
2807
2821
|
if (this.flow_.propagateUnhandledRejections_) {
|
|
@@ -2812,13 +2826,13 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2812
2826
|
this.flow_.reportUncaughtException_(errorToReport);
|
|
2813
2827
|
return false;
|
|
2814
2828
|
}
|
|
2815
|
-
}
|
|
2829
|
+
}
|
|
2816
2830
|
|
|
2817
2831
|
/**
|
|
2818
2832
|
* @param {!Task} task The task to drop.
|
|
2819
2833
|
* @private
|
|
2820
2834
|
*/
|
|
2821
|
-
dropTask_
|
|
2835
|
+
dropTask_(task) {
|
|
2822
2836
|
var index;
|
|
2823
2837
|
if (this.interrupts_) {
|
|
2824
2838
|
index = this.interrupts_.indexOf(task);
|
|
@@ -2834,49 +2848,49 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2834
2848
|
task.queue = null;
|
|
2835
2849
|
this.tasks_.splice(index, 1);
|
|
2836
2850
|
}
|
|
2837
|
-
}
|
|
2851
|
+
}
|
|
2838
2852
|
|
|
2839
2853
|
/**
|
|
2840
2854
|
* @param {!Task} task The task that was cancelled.
|
|
2841
|
-
* @param {!
|
|
2855
|
+
* @param {!CancellationError} reason The cancellation reason.
|
|
2842
2856
|
* @private
|
|
2843
2857
|
*/
|
|
2844
|
-
onTaskCancelled_
|
|
2858
|
+
onTaskCancelled_(task, reason) {
|
|
2845
2859
|
if (this.pending_ && this.pending_.task === task) {
|
|
2846
2860
|
this.pending_.q.abort_(reason);
|
|
2847
2861
|
} else {
|
|
2848
2862
|
this.dropTask_(task);
|
|
2849
2863
|
}
|
|
2850
|
-
}
|
|
2864
|
+
}
|
|
2851
2865
|
|
|
2852
2866
|
/**
|
|
2853
2867
|
* @param {*} value the value originally returned by the task function.
|
|
2854
2868
|
* @private
|
|
2855
2869
|
*/
|
|
2856
|
-
onTaskComplete_
|
|
2870
|
+
onTaskComplete_(value) {
|
|
2857
2871
|
if (this.pending_) {
|
|
2858
2872
|
this.pending_.task.fulfill(value);
|
|
2859
2873
|
}
|
|
2860
|
-
}
|
|
2874
|
+
}
|
|
2861
2875
|
|
|
2862
2876
|
/**
|
|
2863
2877
|
* @param {*} taskFnResult the value originally returned by the task function.
|
|
2864
2878
|
* @param {*} error the error that caused the task function to terminate.
|
|
2865
2879
|
* @private
|
|
2866
2880
|
*/
|
|
2867
|
-
onTaskFailure_
|
|
2868
|
-
if (
|
|
2869
|
-
taskFnResult.cancel(
|
|
2881
|
+
onTaskFailure_(taskFnResult, error) {
|
|
2882
|
+
if (Thenable.isImplementation(taskFnResult)) {
|
|
2883
|
+
taskFnResult.cancel(CancellationError.wrap(error));
|
|
2870
2884
|
}
|
|
2871
2885
|
this.pending_.task.reject(error);
|
|
2872
|
-
}
|
|
2886
|
+
}
|
|
2873
2887
|
|
|
2874
2888
|
/**
|
|
2875
2889
|
* @return {(Task|undefined)} the next task scheduled within this queue,
|
|
2876
2890
|
* if any.
|
|
2877
2891
|
* @private
|
|
2878
2892
|
*/
|
|
2879
|
-
getNextTask_
|
|
2893
|
+
getNextTask_() {
|
|
2880
2894
|
var task = undefined;
|
|
2881
2895
|
while (true) {
|
|
2882
2896
|
if (this.interrupts_) {
|
|
@@ -2896,15 +2910,15 @@ var TaskQueue = goog.defineClass(EventEmitter, {
|
|
|
2896
2910
|
}
|
|
2897
2911
|
return task;
|
|
2898
2912
|
}
|
|
2899
|
-
}
|
|
2913
|
+
};
|
|
2900
2914
|
|
|
2901
2915
|
|
|
2902
2916
|
|
|
2903
2917
|
/**
|
|
2904
2918
|
* The default flow to use if no others are active.
|
|
2905
|
-
* @type {!
|
|
2919
|
+
* @type {!ControlFlow}
|
|
2906
2920
|
*/
|
|
2907
|
-
var defaultFlow = new
|
|
2921
|
+
var defaultFlow = new ControlFlow();
|
|
2908
2922
|
|
|
2909
2923
|
|
|
2910
2924
|
/**
|
|
@@ -2912,48 +2926,48 @@ var defaultFlow = new promise.ControlFlow();
|
|
|
2912
2926
|
* commands. When there are multiple flows on the stack, the flow at index N
|
|
2913
2927
|
* represents a callback triggered within a task owned by the flow at index
|
|
2914
2928
|
* N-1.
|
|
2915
|
-
* @type {!Array<!
|
|
2929
|
+
* @type {!Array<!ControlFlow>}
|
|
2916
2930
|
*/
|
|
2917
2931
|
var activeFlows = [];
|
|
2918
2932
|
|
|
2919
2933
|
|
|
2920
2934
|
/**
|
|
2921
2935
|
* Changes the default flow to use when no others are active.
|
|
2922
|
-
* @param {!
|
|
2936
|
+
* @param {!ControlFlow} flow The new default flow.
|
|
2923
2937
|
* @throws {Error} If the default flow is not currently active.
|
|
2924
2938
|
*/
|
|
2925
|
-
|
|
2939
|
+
function setDefaultFlow(flow) {
|
|
2926
2940
|
if (activeFlows.length) {
|
|
2927
2941
|
throw Error('You may only change the default flow while it is active');
|
|
2928
2942
|
}
|
|
2929
2943
|
defaultFlow = flow;
|
|
2930
|
-
}
|
|
2944
|
+
}
|
|
2931
2945
|
|
|
2932
2946
|
|
|
2933
2947
|
/**
|
|
2934
|
-
* @return {!
|
|
2948
|
+
* @return {!ControlFlow} The currently active control flow.
|
|
2935
2949
|
*/
|
|
2936
|
-
|
|
2937
|
-
return /** @type {!
|
|
2938
|
-
|
|
2939
|
-
}
|
|
2950
|
+
function controlFlow() {
|
|
2951
|
+
return /** @type {!ControlFlow} */ (
|
|
2952
|
+
activeFlows.length ? activeFlows[activeFlows.length - 1] : defaultFlow);
|
|
2953
|
+
}
|
|
2940
2954
|
|
|
2941
2955
|
|
|
2942
2956
|
/**
|
|
2943
2957
|
* Creates a new control flow. The provided callback will be invoked as the
|
|
2944
2958
|
* first task within the new flow, with the flow as its sole argument. Returns
|
|
2945
2959
|
* a promise that resolves to the callback result.
|
|
2946
|
-
* @param {function(!
|
|
2960
|
+
* @param {function(!ControlFlow)} callback The entry point
|
|
2947
2961
|
* to the newly created flow.
|
|
2948
|
-
* @return {!
|
|
2962
|
+
* @return {!ManagedPromise} A promise that resolves to the callback
|
|
2949
2963
|
* result.
|
|
2950
2964
|
*/
|
|
2951
|
-
|
|
2952
|
-
var flow = new
|
|
2965
|
+
function createFlow(callback) {
|
|
2966
|
+
var flow = new ControlFlow;
|
|
2953
2967
|
return flow.execute(function() {
|
|
2954
2968
|
return callback(flow);
|
|
2955
2969
|
});
|
|
2956
|
-
}
|
|
2970
|
+
}
|
|
2957
2971
|
|
|
2958
2972
|
|
|
2959
2973
|
/**
|
|
@@ -2961,9 +2975,9 @@ promise.createFlow = function(callback) {
|
|
|
2961
2975
|
* @param {!Function} fn The function to test.
|
|
2962
2976
|
* @return {boolean} Whether the function is a generator.
|
|
2963
2977
|
*/
|
|
2964
|
-
|
|
2978
|
+
function isGenerator(fn) {
|
|
2965
2979
|
return fn.constructor.name === 'GeneratorFunction';
|
|
2966
|
-
}
|
|
2980
|
+
}
|
|
2967
2981
|
|
|
2968
2982
|
|
|
2969
2983
|
/**
|
|
@@ -2992,7 +3006,7 @@ promise.isGenerator = function(fn) {
|
|
|
2992
3006
|
* yield promise.delayed(250).then(function() {
|
|
2993
3007
|
* throw Error('boom');
|
|
2994
3008
|
* });
|
|
2995
|
-
* }).
|
|
3009
|
+
* }).catch(function(e) {
|
|
2996
3010
|
* console.log(e.toString()); // Error: boom
|
|
2997
3011
|
* });
|
|
2998
3012
|
*
|
|
@@ -3000,18 +3014,19 @@ promise.isGenerator = function(fn) {
|
|
|
3000
3014
|
* @param {Object=} opt_self The object to use as "this" when invoking the
|
|
3001
3015
|
* initial generator.
|
|
3002
3016
|
* @param {...*} var_args Any arguments to pass to the initial generator.
|
|
3003
|
-
* @return {!
|
|
3017
|
+
* @return {!ManagedPromise<?>} A promise that will resolve to the
|
|
3004
3018
|
* generator's final result.
|
|
3005
3019
|
* @throws {TypeError} If the given function is not a generator.
|
|
3006
3020
|
*/
|
|
3007
|
-
|
|
3008
|
-
if (!
|
|
3021
|
+
function consume(generatorFn, opt_self, var_args) {
|
|
3022
|
+
if (!isGenerator(generatorFn)) {
|
|
3009
3023
|
throw new TypeError('Input is not a GeneratorFunction: ' +
|
|
3010
3024
|
generatorFn.constructor.name);
|
|
3011
3025
|
}
|
|
3012
3026
|
|
|
3013
|
-
var deferred =
|
|
3014
|
-
var generator = generatorFn.apply(
|
|
3027
|
+
var deferred = defer();
|
|
3028
|
+
var generator = generatorFn.apply(
|
|
3029
|
+
opt_self, Array.prototype.slice.call(arguments, 2));
|
|
3015
3030
|
callNext();
|
|
3016
3031
|
return deferred.promise;
|
|
3017
3032
|
|
|
@@ -3044,6 +3059,35 @@ promise.consume = function(generatorFn, opt_self, var_args) {
|
|
|
3044
3059
|
return;
|
|
3045
3060
|
}
|
|
3046
3061
|
|
|
3047
|
-
|
|
3062
|
+
asap(result.value, callNext, callThrow);
|
|
3048
3063
|
}
|
|
3049
|
-
}
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
|
|
3067
|
+
// PUBLIC API
|
|
3068
|
+
|
|
3069
|
+
|
|
3070
|
+
exports.CancellationError = CancellationError;
|
|
3071
|
+
exports.ControlFlow = ControlFlow;
|
|
3072
|
+
exports.Deferred = Deferred;
|
|
3073
|
+
exports.MultipleUnhandledRejectionError = MultipleUnhandledRejectionError;
|
|
3074
|
+
exports.Thenable = Thenable;
|
|
3075
|
+
exports.Promise = ManagedPromise;
|
|
3076
|
+
exports.all = all;
|
|
3077
|
+
exports.asap = asap;
|
|
3078
|
+
exports.captureStackTrace = captureStackTrace;
|
|
3079
|
+
exports.checkedNodeCall = checkedNodeCall;
|
|
3080
|
+
exports.consume = consume;
|
|
3081
|
+
exports.controlFlow = controlFlow;
|
|
3082
|
+
exports.createFlow = createFlow;
|
|
3083
|
+
exports.defer = defer;
|
|
3084
|
+
exports.delayed = delayed;
|
|
3085
|
+
exports.filter = filter;
|
|
3086
|
+
exports.fulfilled = fulfilled;
|
|
3087
|
+
exports.fullyResolved = fullyResolved;
|
|
3088
|
+
exports.isGenerator = isGenerator;
|
|
3089
|
+
exports.isPromise = isPromise;
|
|
3090
|
+
exports.map = map;
|
|
3091
|
+
exports.rejected = rejected;
|
|
3092
|
+
exports.setDefaultFlow = setDefaultFlow;
|
|
3093
|
+
exports.when = when;
|