1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * Helpers for async functions. Async functions are generator functions that are
9 * run by Tasks. An async function returns a Promise for the resolution of the
10 * function. When the function returns, the promise is resolved with the
11 * returned value. If it throws the promise rejects with the thrown error.
13 * See Task documentation at https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Task.jsm.
16 let {Cu} = require("chrome");
17 let {Task} = require("resource://gre/modules/Task.jsm");
18 let {Promise} = require("resource://gre/modules/Promise.jsm");
21 * Create an async function from a generator function.
23 * @param Function func
24 * The generator function that to wrap as an async function.
28 exports.async = function async(func) {
29 return function(...args) {
30 return Task.spawn(func.apply(this, args));
35 * Create an async function that only executes once per instance of an object.
36 * Once called on a given object, the same promise will be returned for any
37 * future calls for that object.
39 * @param Function func
40 * The generator function that to wrap as an async function.
44 exports.asyncOnce = function asyncOnce(func) {
45 const promises = new WeakMap();
46 return function(...args) {
47 let promise = promises.get(this);
49 promise = Task.spawn(func.apply(this, args));
50 promises.set(this, promise);
57 * Adds an event listener to the given element, and then removes its event
58 * listener once the event is called, returning the event object as a promise.
59 * @param nsIDOMElement element
60 * The DOM element to listen on
62 * The name of the event type to listen for
63 * @param Boolean useCapture
64 * Should we initiate the capture phase?
66 * The promise resolved with the event object when the event first
69 exports.listenOnce = function listenOnce(element, event, useCapture) {
70 return new Promise(function(resolve, reject) {
71 var onEvent = function(ev) {
72 element.removeEventListener(event, onEvent, useCapture);
75 element.addEventListener(event, onEvent, useCapture);
80 * Call a function that expects a callback as the last argument and returns a
81 * promise for the result. This simplifies using callback APIs from tasks and
85 * The |this| value to call the function on.
86 * @param Function func
87 * The callback-expecting function to call.
89 * Additional arguments to pass to the method.
91 * The promise for the result. If the callback is called with only one
92 * argument, it is used as the resolution value. If there's multiple
93 * arguments, an array containing the arguments is the resolution value.
94 * If the method throws, the promise is rejected with the thrown value.
96 function promisify(obj, func, args) {
97 return new Promise(resolve => {
98 args.push((...results) => {
99 resolve(results.length > 1 ? results : results[0]);
101 func.apply(obj, args);
106 * Call a method that expects a callback as the last argument and returns a
107 * promise for the result.
111 exports.promiseInvoke = function promiseInvoke(obj, func, ...args) {
112 return promisify(obj, func, args);
116 * Call a function that expects a callback as the last argument.
120 exports.promiseCall = function promiseCall(func, ...args) {
121 return promisify(undefined, func, args);