]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/promises.jsm
Imported Upstream version 1.1+hg7904
[dactyl.git] / common / modules / promises.jsm
1 // Copyright (c) 2014 Kris Maglione <maglione.k at Gmail>
2 //
3 // This work is licensed for reuse under an MIT license. Details are
4 // given in the LICENSE.txt file included with this file.
5 "use strict";
6
7 defineModule("promises", {
8     exports: ["Promise", "Task", "promises"],
9     require: []
10 });
11
12 lazyRequire("services", ["services"]);
13
14 lazyRequire("resource://gre/modules/Promise.jsm", ["Promise"]);
15 lazyRequire("resource://gre/modules/Task.jsm", ["Task"]);
16
17 function withCallbacks(fn) {
18     return function wrapper(...args) {
19         let deferred = Promise.defer();
20         function resolve(arg) { deferred.resolve(arg); }
21         function reject(arg)  { deferred.reject(arg); }
22         fn.apply(this, [[resolve, reject, deferred]].concat(args));
23         return deferred.promise;
24     }
25 }
26
27 var Promises = Module("Promises", {
28     _cancel: WeakMap(),
29
30     /**
31      * Allows promises to be canceled..
32      *
33      * @param {Promise} promise The promise to cancel.
34      * @param {*} arg Argument to be passed to the cancellation
35      * function.
36      */
37     cancel: function cancel(promise, reason) {
38         let cleanup = this._cancel.get(promise);
39         if (cleanup) {
40             cleanup[0](promise);
41             cleanup[1].reject(reason);
42         }
43         this._cancel.delete(promise);
44     },
45
46     /**
47      * Registers a cleanup function for the given deferred promise.
48      *
49      * @param {Deferred} promise The promise to cancel.
50      * @param {function} fn The cleanup function.
51      */
52     oncancel: function oncancel(deferred, fn) {
53         this._cancel.set(deferred.promise, [fn, deferred]);
54     },
55
56     /**
57      * Returns a promise which resolves after a brief delay.
58      */
59     delay: withCallbacks(function delay([accept]) {
60         let { mainThread } = services.threading;
61         mainThread.dispatch(accept, mainThread.DISPATCH_NORMAL);
62     }),
63
64     /**
65      * Returns a promise which resolves with the given argument.
66      */
67     accept: function fail(arg) {
68         let deferred = Promise.defer();
69         deferred.resolve(arg);
70         return deferred.promise;
71     },
72
73     /**
74      * Returns a promise which fails with the given argument.
75      */
76     fail: function fail(arg) {
77         let deferred = Promise.defer();
78         deferred.reject(arg);
79         return deferred.promise;
80     },
81
82     /**
83      * Returns a promise which resolves after the given number of
84      * milliseconds.
85      *
86      * @param {number} delay The number of milliseconds to wait.
87      */
88     sleep: withCallbacks(function sleep([callback], delay) {
89         this.timeout(callback, delay);
90     }),
91
92     /**
93      * Wraps the given function so that each call spawns a Task.
94      *
95      * @param {function} fn The function to wrap.
96      * @returns {function}
97      */
98     task: function task(fn) {
99         return function task_(...args) {
100             return Task.spawn(fn.bind.apply(fn, [this].concat(args)));
101         }
102     },
103
104     /**
105      * Returns a promise which resolves when the function *test* returns
106      * true, or *timeout* milliseconds have expired.
107      *
108      * @param {function} test The predicate on which to wait.
109      * @param {Number} timeout The maximum number of milliseconds to
110      *      wait.
111      *      @optional
112      * @param {number} pollInterval The poll interval, in milliseconds.
113      *      @default 10
114      */
115     waitFor: withCallbacks(function waitFor([accept, reject], test, timeout=null, pollInterval=10) {
116         let end = timeout && Date.now() + timeout, result;
117
118         let timer = services.Timer(
119             () => {
120                 try {
121                     var result = test();
122                 }
123                 catch (e) {
124                     timer.cancel();
125                     reject(e);
126                 }
127                 if (result) {
128                     timer.cancel();
129                     accept(result);
130                 }
131             },
132             pollInterval, services.Timer.TYPE_REPEATING_SLACK);
133     }),
134
135     /**
136      * Wraps the given function so that its first argument is an array
137      * of success and failure callbacks which, when called, resolve the
138      * returned promise.
139      *
140      * @param {function} fn The function to wrap.
141      * @returns {Promise}
142      */
143     withCallbacks: withCallbacks,
144 });
145
146 endModule();
147
148 // vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: