From 2138c2746d599aac117effce860590c22c253aeb Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 16 Nov 2015 10:10:46 -0500 Subject: [PATCH] Adding XHR support --- .gitignore | 1 + .npmignore | 3 ++ README.md | 1 + can-wait.js | 95 ++++++++++++++++++++++++++++++++++------------------ demo.html | 3 +- demo.js | 3 +- package.json | 7 ++-- 7 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 .gitignore create mode 100644 .npmignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..b0d3ece --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +test/ +demo.html +demo.js diff --git a/README.md b/README.md index 6c29f7f..6643803 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ For can-wait to work we have to override various task-creating functionality, th **Macrotasks** * setTimeout +* XMLHttpRequest **Microtasks** diff --git a/can-wait.js b/can-wait.js index ca2cb19..56e9ecd 100644 --- a/can-wait.js +++ b/can-wait.js @@ -12,6 +12,15 @@ function Deferred(){ }); } +var waitWithinRequest = g.canWait = function(fn){ + var request = waitWithinRequest.currentRequest; + request.waits++; + + return function(){ + return request.run(fn, this, arguments); + }; +}; + function Override(obj, name, fn) { this.old = obj[name]; this.obj = obj; @@ -27,80 +36,102 @@ Override.prototype.release = function(){ this.obj[this.name] = this.old; }; -var overrideSetTimeout = function(overrides){ +var overrideSetTimeout = function(request){ return new Override(g, "setTimeout", function(setTimeout){ return function(fn, timeout){ - var dfd = new Deferred(); - overrides.promises.push(dfd.promise); - - return setTimeout.call(this, function(){ - return overrides.run(fn, dfd); - }, timeout); + var callback = waitWithinRequest(fn); + return setTimeout.call(this, callback, timeout); } }); }; -var overrideRAF = function(overrides){ +var overrideRAF = function(request){ return new Override(g, "requestAnimationFrame", function(rAF){ return function(fn){ - var dfd = new Deferred(); - overrides.promises.push(dfd.promise); + var callback = waitWithinRequest(fn); + return rAF.call(this, callback); + }; + }); +}; - return rAF.call(this, function(){ - return overrides.run(fn, dfd); +var overrideXHR = function(request){ + return new Override(XMLHttpRequest.prototype, "send", function(send){ + return function(){ + var onreadystatechange = this.onreadystatechange, + onload = this.onload, + onerror = this.onerror, + error; + + var request = waitWithinRequest.currentRequest; + var callback = waitWithinRequest(function(){ + if(this.readyState === 4) { + onreadystatechange && onreadystatechange.apply(this, arguments); + + if(error) + onerror && onerror.apply(this, arguments); + else + onload && onload.apply(this, arguments); + } else { + request.waits++; + } }); + this.onreadystatechange = callback; + this.onerror = function(err){ error = err }; + + return send.apply(this, arguments); }; }); }; -function OverrideCollection() { +function Request() { + this.deferred = new Deferred(); this.promises = []; + this.waits = 0; var o = this.overrides = []; o.push(overrideSetTimeout(this)); o.push(overrideRAF(this)); + o.push(overrideXHR(this)); } -OverrideCollection.prototype.trap = function(){ +Request.prototype.trap = function(){ var o = this.overrides; for(var i = 0, len = o.length; i < len; i++) { o[i].trap(); } }; -OverrideCollection.prototype.release = function(){ +Request.prototype.release = function(){ var o = this.overrides; for(var i = 0, len = o.length; i < len; i++) { o[i].release(); } }; -OverrideCollection.prototype.run = function(fn, dfd){ +Request.prototype.run = function(fn, ctx, args){ + var res = this.runWithinScope(fn, ctx, args); + this.waits--; + if(this.waits === 0) { + this.deferred.resolve(); + } + return res; +}; + +Request.prototype.runWithinScope = function(fn, ctx, args){ + waitWithinRequest.currentRequest = this; this.trap(); - var res = fn(); + var res = fn.apply(ctx, args); this.release(); - if(dfd) - dfd.resolve(); return res; }; function canWait(fn) { - var overrides = new OverrideCollection(); + var request = new Request(); // Call the function - overrides.run(fn); + request.runWithinScope(fn); - function waitOnAll() { - var promises = overrides.promises; - if(promises.length) { - var waiting = [].slice.call(promises); - promises.length = 0; - - return Promise.all(waiting).then(waitOnAll); - } - return Promise.resolve(); - } - return waitOnAll(); + return request.deferred.promise; } if(typeof module !== "undefined" && module.exports) { diff --git a/demo.html b/demo.html index 5a4aa9e..f5ba6b0 100644 --- a/demo.html +++ b/demo.html @@ -15,7 +15,6 @@ - - + diff --git a/demo.js b/demo.js index 0f846af..a3fe696 100644 --- a/demo.js +++ b/demo.js @@ -1,3 +1,5 @@ +var canWait = require("can-wait"); + var results = []; var requests = [ @@ -35,7 +37,6 @@ var requests = [ setTimeout(function(){ results.push("2-c"); }); - }, function(results) { diff --git a/package.json b/package.json index a42eb7b..ffbf6a1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "can-wait", "version": "0.0.1", "description": "Asynchronous render for all frameworks", - "main": "wait.js", + "main": "can-wait.js", "scripts": { "test": "node test/test.js" }, @@ -22,5 +22,8 @@ "bugs": { "url": "https://github.com/canjs/can-wait/issues" }, - "homepage": "https://github.com/canjs/can-wait#readme" + "homepage": "https://github.com/canjs/can-wait#readme", + "devDependencies": { + "steal": "^0.12.4" + } }