diff --git a/toolkit/modules/Promise.jsm b/toolkit/modules/Promise.jsm index f1ba862eae7..142b7642fe5 100755 --- a/toolkit/modules/Promise.jsm +++ b/toolkit/modules/Promise.jsm @@ -442,14 +442,6 @@ Promise.defer = function () */ Promise.resolve = function (aValue) { - if (aValue && typeof(aValue) == "function" && aValue.isAsyncFunction) { - throw new TypeError( - "Cannot resolve a promise with an async function. " + - "You should either invoke the async function first " + - "or use 'Task.spawn' instead of 'Task.async' to start " + - "the Task and return its promise."); - } - return new Promise((aResolve) => aResolve(aValue)); }; diff --git a/toolkit/modules/Task.jsm b/toolkit/modules/Task.jsm index 5031b4c5315..fe5127ac2b6 100644 --- a/toolkit/modules/Task.jsm +++ b/toolkit/modules/Task.jsm @@ -136,53 +136,24 @@ this.Task = { * called when the task terminates. */ spawn: function Task_spawn(aTask) { - return createAsyncFunction(aTask).call(undefined); - }, - - /** - * Create and return an 'async function' that starts a new task. - * - * This is similar to 'spawn' except that it doesn't immediately start - * the task, it binds the task to the async function's 'this' object and - * arguments, and it requires the task to be a function. - * - * It simplifies the common pattern of implementing a method via a task, - * like this simple object with a 'greet' method that has a 'name' parameter - * and spawns a task to send a greeting and return its reply: - * - * let greeter = { - * message: "Hello, NAME!", - * greet: function(name) { - * return Task.spawn((function* () { - * return yield sendGreeting(this.message.replace(/NAME/, name)); - * }).bind(this); - * }) - * }; - * - * With Task.async, the method can be declared succinctly: - * - * let greeter = { - * message: "Hello, NAME!", - * greet: Task.async(function* (name) { - * return yield sendGreeting(this.message.replace(/NAME/, name)); - * }) - * }; - * - * While maintaining identical semantics: - * - * greeter.greet("Mitchell").then((reply) => { ... }); // behaves the same - * - * @param aTask - * The task function to start. - * - * @return A function that starts the task function and returns its promise. - */ - async: function Task_async(aTask) { - if (typeof(aTask) != "function") { - throw new TypeError("aTask argument must be a function"); + if (aTask && typeof(aTask) == "function") { + try { + // Let's call into the function ourselves. + aTask = aTask(); + } catch (ex if ex instanceof Task.Result) { + return Promise.resolve(ex.value); + } catch (ex) { + return Promise.reject(ex); + } } - return createAsyncFunction(aTask); + if (isGenerator(aTask)) { + // This is an iterator resulting from calling a generator function. + return new TaskImpl(aTask).deferred.promise; + } + + // Just propagate the given value to the caller as a resolved promise. + return Promise.resolve(aTask); }, /** @@ -197,42 +168,6 @@ this.Task = { } }; -function createAsyncFunction(aTask) { - let asyncFunction = function () { - let result = aTask; - if (aTask && typeof(aTask) == "function") { - if (aTask.isAsyncFunction) { - throw new TypeError( - "Cannot use an async function in place of a promise. " + - "You should either invoke the async function first " + - "or use 'Task.spawn' instead of 'Task.async' to start " + - "the Task and return its promise."); - } - - try { - // Let's call into the function ourselves. - result = aTask.apply(this, arguments); - } catch (ex if ex instanceof Task.Result) { - return Promise.resolve(ex.value); - } catch (ex) { - return Promise.reject(ex); - } - } - - if (isGenerator(result)) { - // This is an iterator resulting from calling a generator function. - return new TaskImpl(result).deferred.promise; - } - - // Just propagate the given value to the caller as a resolved promise. - return Promise.resolve(result); - }; - - asyncFunction.isAsyncFunction = true; - - return asyncFunction; -} - //////////////////////////////////////////////////////////////////////////////// //// TaskImpl diff --git a/toolkit/modules/tests/xpcshell/test_Promise.js b/toolkit/modules/tests/xpcshell/test_Promise.js index 2836c647728..fe91a04a258 100644 --- a/toolkit/modules/tests/xpcshell/test_Promise.js +++ b/toolkit/modules/tests/xpcshell/test_Promise.js @@ -4,7 +4,6 @@ Components.utils.import("resource://gre/modules/Promise.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://gre/modules/Task.jsm"); //////////////////////////////////////////////////////////////////////////////// //// Test runner @@ -528,14 +527,6 @@ tests.push( return promise; })); -// Test that Promise.resolve throws when its argument is an async function. -tests.push( - make_promise_test(function test_promise_resolve_throws_with_async_function(test) { - Assert.throws(() => Promise.resolve(Task.async(function* () {})), - /Cannot resolve a promise with an async function/); - return Promise.resolve(); - })); - // Test that the code after "then" is always executed before the callbacks tests.push( make_promise_test(function then_returns_before_callbacks(test) { diff --git a/toolkit/modules/tests/xpcshell/test_task.js b/toolkit/modules/tests/xpcshell/test_task.js index 4be9478f649..f82cdbd8ce7 100644 --- a/toolkit/modules/tests/xpcshell/test_task.js +++ b/toolkit/modules/tests/xpcshell/test_task.js @@ -118,36 +118,6 @@ add_test(function test_spawn_function() }); }); -add_test(function test_spawn_function_this() -{ - Task.spawn(function () { - return this; - }).then(function (result) { - // Since the task function wasn't defined in strict mode, its "this" object - // should be the same as the "this" object in this function, i.e. the global - // object. - do_check_eq(result, this); - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - -add_test(function test_spawn_function_this_strict() -{ - "use strict"; - Task.spawn(function () { - return this; - }).then(function (result) { - // Since the task function was defined in strict mode, its "this" object - // should be undefined. - do_check_eq(typeof(result), "undefined"); - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - add_test(function test_spawn_function_returning_promise() { Task.spawn(function () { @@ -272,116 +242,3 @@ add_test(function test_mixed_legacy_and_star() do_throw("Unexpected error: " + ex); }); }); - -add_test(function test_async_function_from_generator() -{ - Task.spawn(function* () { - let object = { - asyncFunction: Task.async(function* (param) { - do_check_eq(this, object); - return param; - }) - }; - - // Ensure the async function returns a promise that resolves as expected. - do_check_eq((yield object.asyncFunction(1)), 1); - - // Ensure a second call to the async function also returns such a promise. - do_check_eq((yield object.asyncFunction(3)), 3); - }).then(function () { - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - -add_test(function test_async_function_from_function() -{ - Task.spawn(function* () { - return Task.spawn(function* () { - let object = { - asyncFunction: Task.async(function (param) { - do_check_eq(this, object); - return param; - }) - }; - - // Ensure the async function returns a promise that resolves as expected. - do_check_eq((yield object.asyncFunction(5)), 5); - - // Ensure a second call to the async function also returns such a promise. - do_check_eq((yield object.asyncFunction(7)), 7); - }); - }).then(function () { - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - -add_test(function test_async_function_that_throws_rejects_promise() -{ - Task.spawn(function* () { - let object = { - asyncFunction: Task.async(function* () { - throw "Rejected!"; - }) - }; - - yield object.asyncFunction(); - }).then(function () { - do_throw("unexpected success calling async function that throws error"); - }, function (ex) { - do_check_eq(ex, "Rejected!"); - run_next_test(); - }); -}); - -add_test(function test_async_return_function() -{ - Task.spawn(function* () { - // Ensure an async function that returns a function resolves to the function - // itself instead of calling the function and resolving to its return value. - return Task.spawn(function* () { - let returnValue = function () { - return "These aren't the droids you're looking for."; - }; - - let asyncFunction = Task.async(function () { - return returnValue; - }); - - do_check_eq((yield asyncFunction()), returnValue); - }); - }).then(function () { - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - -add_test(function test_async_throw_argument_not_function() -{ - Task.spawn(function* () { - // Ensure Task.async throws if its aTask argument is not a function. - Assert.throws(() => Task.async("not a function"), - /aTask argument must be a function/); - }).then(function () { - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -}); - -add_test(function test_async_throw_on_function_in_place_of_promise() -{ - Task.spawn(function* () { - // Ensure Task.spawn throws if passed an async function. - Assert.throws(() => Task.spawn(Task.async(function* () {})), - /Cannot use an async function in place of a promise/); - }).then(function () { - run_next_test(); - }, function (ex) { - do_throw("Unexpected error: " + ex); - }); -});