Browse Source

Remove Sync().onComplete functionality changing ability and replace with Sync.withCb().

Edward Lee 15 years ago
parent
commit
86c252fdd0
2 changed files with 47 additions and 46 deletions
  1. 37 35
      Sync.js
  2. 10 11
      test/unit/test_Sync.js

+ 37 - 35
Sync.js

@@ -47,6 +47,22 @@ const Cu = Components.utils;
 const CB_READY = {};
 const CB_COMPLETE = {};
 
+/**
+ * Create a callback that remembers state like whether it's been called
+ */
+function makeCallback() {
+  // The main callback remembers the value it's passed and that it got data
+  let onComplete = function Sync_onComplete(data) {
+    onComplete.value = data;
+    onComplete.state = CB_COMPLETE;
+  };
+
+  // Initialize the callback to wait to be called
+  onComplete.state = CB_READY;
+
+  return onComplete;
+}
+
 /**
  * Make a synchronous version of the function object that will be called with
  * the provided thisArg.
@@ -55,39 +71,22 @@ const CB_COMPLETE = {};
  *        The asynchronous function to make a synchronous function
  * @param thisArg {Object} [optional]
  *        The object that the function accesses with "this"
+ * @param callback {Function} [optional] [internal]
+ *        The callback that will trigger the end of the async. call
  * @usage let ret = Sync(asyncFunc, obj)(arg1, arg2);
  * @usage let ret = Sync(ignoreThisFunc)(arg1, arg2);
  * @usage let sync = Sync(async); let ret = sync(arg1, arg2);
  */
-function Sync(func, thisArg) {
-  // Create a callback that remembers its state
-  let makeCallback = function Sync_makeCallback() {
-    // The main callback remembers the value it's passed and that it got data
-    let onComplete = function Sync_onComplete(data) {
-      onComplete.value = data;
-      onComplete.state = CB_COMPLETE;
-    };
-
-    // Initialize the callback to wait to be called
-    onComplete.state = CB_READY;
-
-    return onComplete;
-  };
-
-  // If the sync. function callback is extracted, remember what it is
-  let extractedCallback;
-
-  let syncFunc = function Sync_syncFunc(/* arg1, arg2, ... */) {
+function Sync(func, thisArg, callback) {
+  return function syncFunc(/* arg1, arg2, ... */) {
     // Grab the current thread so we can make it give up priority
     let thread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
 
     // Save the original arguments into an array
     let args = Array.slice(arguments);
 
-    // Track the callback used for this sync. invocation instance
-    let instanceCallback = extractedCallback;
-
-    // We need to add a callback if it wasn't extracted out beforehand
+    let instanceCallback = callback;
+    // We need to create a callback and insert it if we weren't given one
     if (instanceCallback == null) {
       // Create a new callback for this invocation instance and pass it in
       instanceCallback = makeCallback();
@@ -107,20 +106,23 @@ function Sync(func, thisArg) {
     // Return the value passed to the callback
     return instanceCallback.value;
   };
-
-  // Grabbing the onComplete converts the sync. function to not assume the first
-  // argument is our custom callback
-  syncFunc.__defineGetter__("onComplete", function() {
-    // Only allow one callback to be made, so delete the getter immediately
-    delete syncFunc.onComplete;
-
-    // Remember the one callback made as a property and locally
-    return syncFunc.onComplete = extractedCallback = makeCallback();
-  });
-
-  return syncFunc;
 }
 
+/**
+ * Make a synchronous version of an async. function and the callback to trigger
+ * the end of the async. call.
+ *
+ * @param func {Function}
+ *        The asynchronous function to make a synchronous function
+ * @param thisArg {Object} [optional]
+ *        The object that the function accesses with "this"
+ * @usage let [sync, cb] = Sync.withCb(async); let ret = sync(arg1, arg2, cb);
+ */
+Sync.withCb = function Sync_withCb(func, thisArg) {
+  let cb = makeCallback();
+  return [Sync(func, thisArg, cb), cb];
+};
+
 /**
  * Set a timer, simulating the API for the window.setTimeout call.
  * This only simulates the API for the version of the call that accepts

+ 10 - 11
test/unit/test_Sync.js

@@ -61,22 +61,22 @@ function test_Sync_this() {
 }
 
 // Check that sync. function callbacks can be extracted
-function test_Sync_onComplete() {
-  let add = Sync(slowAdd);
+function test_Sync_withCb() {
+  let [add, cb] = Sync.withCb(slowAdd);
   checkTime(function() {
-    let sum = add(add.onComplete, 100, 1000, 234);
+    let sum = add(cb, 100, 1000, 234);
     do_check_eq(sum, 1234);
   }, 100);
 }
 
 // Test sync of async function that indirectly takes the callback
-function test_Sync_onComplete_indirect() {
-  let square = Sync(function(obj) {
+function test_Sync_withCb_indirect() {
+  let [square, cb] = Sync.withCb(function(obj) {
     setTimeout(function() obj.done(obj.num * obj.num), obj.wait);
   });
 
   let thing = {
-    done: square.onComplete,
+    done: cb,
     num: 3,
     wait: 100
   };
@@ -88,9 +88,10 @@ function test_Sync_onComplete_indirect() {
 }
 
 // Test sync of async function that takes no args
-function test_Sync_onComplete_noargs() {
-  let done;
-  let makePi = Sync(function() {
+function test_Sync_withCb_noargs() {
+  // XXX Bug 496134 declare the variable before doing destructured assignment
+  let makePi, done;
+  [makePi, done] = Sync.withCb(function() {
     // Find PI by starting at 0.04 and adding 0.1 31 times
     let pi = 0.04;
     while (pi <= 3.14) {
@@ -100,8 +101,6 @@ function test_Sync_onComplete_noargs() {
     done(pi);
   });
 
-  done = makePi.onComplete;
-
   checkTime(function() {
     let pi = makePi();
     do_check_eq(pi.toFixed(2), "3.14");