Backed out changeset c3cca6dfcaa7 for landing with the wrong bug number.
[gecko.git] / toolkit / devtools / async-utils.js
blobca604a2a0c4af0518c1e11f0b5a1f6e3fc6a25e2
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/. */
5 "use strict";
7 /**
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.
12  *
13  * See Task documentation at https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Task.jsm.
14  */
16 let {Cu} = require("chrome");
17 let {Task} = require("resource://gre/modules/Task.jsm");
18 let {Promise} = require("resource://gre/modules/Promise.jsm");
20 /**
21  * Create an async function from a generator function.
22  *
23  * @param Function func
24  *        The generator function that to wrap as an async function.
25  * @return Function
26  *         The async function.
27  */
28 exports.async = function async(func) {
29   return function(...args) {
30     return Task.spawn(func.apply(this, args));
31   };
34 /**
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.
38  *
39  * @param Function func
40  *        The generator function that to wrap as an async function.
41  * @return Function
42  *         The async function.
43  */
44 exports.asyncOnce = function asyncOnce(func) {
45   const promises = new WeakMap();
46   return function(...args) {
47     let promise = promises.get(this);
48     if (!promise) {
49       promise = Task.spawn(func.apply(this, args));
50       promises.set(this, promise);
51     }
52     return promise;
53   };
56 /**
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
61  * @param  String event
62  *         The name of the event type to listen for
63  * @param  Boolean useCapture
64  *         Should we initiate the capture phase?
65  * @return Promise
66  *         The promise resolved with the event object when the event first
67  *         happens
68  */
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);
73       resolve(ev);
74     }
75     element.addEventListener(event, onEvent, useCapture);
76   });
79 /**
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
82  * async functions.
83  *
84  * @param Any obj
85  *        The |this| value to call the function on.
86  * @param Function func
87  *        The callback-expecting function to call.
88  * @param Array args
89  *        Additional arguments to pass to the method.
90  * @return Promise
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.
95  */
96 function promisify(obj, func, args) {
97   return new Promise(resolve => {
98     args.push((...results) => {
99       resolve(results.length > 1 ? results : results[0]);
100     });
101     func.apply(obj, args);
102   });
106  * Call a method that expects a callback as the last argument and returns a
107  * promise for the result.
109  * @see promisify
110  */
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.
118  * @see promisify
119  */
120 exports.promiseCall = function promiseCall(func, ...args) {
121   return promisify(undefined, func, args);