Skip to content

Commit

Permalink
Merge masters
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal committed Feb 5, 2013
2 parents ea9aae2 + 50cde79 commit e3a927d
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 41 deletions.
80 changes: 57 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ return value (fulfillment) or thrown exception (rejection).
promiseMeSomething()
.then(function (value) {
}, function (reason) {
})
});
```

If ``promiseMeSomething`` returns a promise that gets fulfilled later
Expand All @@ -118,7 +118,7 @@ assigning to ``outputPromise``.
var outputPromise = getInputPromise()
.then(function (input) {
}, function (reason) {
})
});
```

The ``outputPromise`` variable becomes a new promise for the return
Expand All @@ -142,7 +142,7 @@ error handler, the **error** will go to ``outputPromise``:
```javascript
var outputPromise = getInputPromise()
.then(function (value) {
})
});
```

If the input promise gets fulfilled and you omit the value handler, the
Expand All @@ -151,7 +151,7 @@ If the input promise gets fulfilled and you omit the value handler, the
```javascript
var outputPromise = getInputPromise()
.then(null, function (error) {
})
});
```

Q promises provide a ``fail`` shorthand for ``then`` when you are only
Expand All @@ -160,7 +160,7 @@ interested in handling the error:
```javascript
var outputPromise = getInputPromise()
.fail(function (error) {
})
});
```

If you are writing JavaScript for modern engines only or using
Expand All @@ -177,7 +177,7 @@ may be delayed if the final handler returns a promise.
var outputPromise = getInputPromise()
.fin(function () {
// close files, database connections, stop servers, conclude tests
})
});
```

- If the handler returns a value, the value is ignored
Expand Down Expand Up @@ -206,7 +206,7 @@ return getUsername()
// resolves the promise returned
// by the first line
})
})
});
```

```javascript
Expand All @@ -220,7 +220,7 @@ return getUsername()
// or the exception thrown here
// resolves the promise returned
// by the first line
})
});
```

The only difference is nesting. It’s useful to nest handlers if you
Expand Down Expand Up @@ -255,7 +255,7 @@ fulfilled array using ``all``.
return Q.all([
eventualAdd(2, 2),
eventualAdd(10, 20)
])
]);
```

If you have a promise for an array, you can use ``spread`` as a
Expand All @@ -280,7 +280,7 @@ return getUsername()
return [username, getUser(username)];
})
.spread(function (username, user) {
})
});
```

The ``all`` function returns a promise for an array of values. If one
Expand All @@ -299,7 +299,7 @@ Q.allResolved(promises)
var exception = promise.valueOf().exception;
}
})
})
});
```


Expand Down Expand Up @@ -341,12 +341,12 @@ exception in the value handler, it will not be be caught by the error
handler.

```javascript
foo()
return foo()
.then(function (value) {
throw new Error("Can't bar.");
}, function (error) {
// We only get here if "foo" fails
})
});
```

To see why this is, consider the parallel between promises and
Expand All @@ -358,15 +358,41 @@ That code then needs its own ``try``/``catch`` block.
In terms of promises, this means chaining your error handler:

```javascript
foo()
return foo()
.then(function (value) {
throw new Error("Can't bar.");
})
.fail(function (error) {
// We get here with either foo's error or bar's error
})
});
```

### Progress Notification

It's possible for promises to report their progress, e.g. for tasks that take a
long time like a file upload. Not all promises will implement progress
notifications, but for those that do, you can consume the progress values using
a third parameter to ``then``:

```javascript
return uploadFile()
.then(function () {
// Success uploading the file
}, function (err) {
// There was an error, and we get the reason for error
}, function (progress) {
// We get notified of the upload's progress as it is executed
});
```

Like `fail`, Q also provides a shorthand for progress callbacks
called `progress`:

```javascript
return uploadFile().progress(function (progress) {
// We get notified of the upload's progress
});
```

### The End

Expand All @@ -381,7 +407,7 @@ So, either return it,
return foo()
.then(function () {
return "bar";
})
});
```

Or, end it.
Expand All @@ -391,7 +417,7 @@ foo()
.then(function () {
return "bar";
})
.done()
.done();
```

Ending a promise chain makes sure that, if an error doesn’t get
Expand Down Expand Up @@ -423,7 +449,7 @@ You can also use ``fcall`` to get a promise for an exception.
```javascript
return Q.fcall(function () {
throw new Error("Can't do it");
})
});
```

As the name implies, ``fcall`` can call functions, or even promised
Expand Down Expand Up @@ -491,6 +517,9 @@ function timeout(promise, ms) {
}
```

Finally, you can send a progress notification to the promise with
``deferred.notify``.

For illustration, this is a wrapper for XML HTTP requests in the browser. Note
that a more [thorough][XHR] implementation would be in order in practice.

Expand All @@ -504,6 +533,7 @@ function requestOkText(url) {
request.open("GET", url, true);
request.onload = onload;
request.onerror = onerror;
request.onprogress = onprogress;
request.send();

function onload() {
Expand All @@ -518,8 +548,12 @@ function requestOkText(url) {
deferred.reject("Can't XHR " + JSON.stringify(url));
}

function onprogress(event) {
deferred.notify(event.loaded / event.total);
}

return deferred.promise;
};
}
```


Expand Down Expand Up @@ -562,7 +596,7 @@ This thankfully is all we need to turn them into vibrant Q promises.
```javascript
return Q.when($.ajax(...))
.then(function () {
})
});
```

If there is any chance that the promise you receive is not a Q promise
Expand All @@ -572,7 +606,7 @@ You can even use ``Q.invoke`` as a shorthand.
```javascript
return Q.invoke($, 'ajax', ...)
.then(function () {
})
});
```


Expand Down Expand Up @@ -611,7 +645,7 @@ return Q.fcall(function () {
})
.then(function (value) {
return value[0].foo;
})
});
```

with
Expand All @@ -621,7 +655,7 @@ return Q.fcall(function () {
return [{ foo: "bar" }, { foo: "baz" }];
})
.get(0)
.get("foo")
.get("foo");
```


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"devDependencies": {
"jshint": ">=0.9.1",
"cover": "*",
"jasmine-node": "*",
"jasmine-node": "1.2.2",
"opener": "*",
"promises-aplus-tests": "~1.0"
},
Expand Down
12 changes: 10 additions & 2 deletions q.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ if (typeof process !== "undefined") {
nextTick = process.nextTick;
} else if (typeof setImmediate === "function") {
// In IE10, or use https://github.com/NobleJS/setImmediate
nextTick = setImmediate;
if (typeof window !== "undefined") {
nextTick = setImmediate.bind(window);
} else {
nextTick = setImmediate;
}
} else if (typeof MessageChannel !== "undefined") {
// modern browsers
// http://www.nonblocking.io/2011/06/windownexttick.html
Expand Down Expand Up @@ -186,10 +190,14 @@ var object_create = Object.create || function (prototype) {
return new Type();
};

var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);

var object_keys = Object.keys || function (object) {
var keys = [];
for (var key in object) {
keys.push(key);
if (object_hasOwnProperty(object, key)) {
keys.push(key);
}
}
return keys;
};
Expand Down
34 changes: 19 additions & 15 deletions spec/q-spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use strict";
/*jshint newcap: false*/
/*global Q: true, describe: false, it: false, expect: false, afterEach: false,
require: false, jasmine: false, waitsFor: false, runs: false */
/*global Q: true, describe: false, it: false, expect: false, beforeEach: false,
afterEach: false, require: false, jasmine: false, waitsFor: false,
runs: false */

if (typeof Q === "undefined" && typeof require !== "undefined") {
// For Node compatibility.
Expand All @@ -11,6 +12,10 @@ if (typeof Q === "undefined" && typeof require !== "undefined") {

var REASON = "this is not an error, but it might show up in the console";

var STRICT_MODE_CAPABLE = (function(){
return !this;
})();

afterEach(function () {
Q.onerror = null;
});
Expand Down Expand Up @@ -239,6 +244,9 @@ describe("progress", function () {
progressed1 = true;
}
);

Q.onerror = function () { };

Q.when(deferred.promise, null, null, function () {
progressed2 = true;
throw new Error("just a test, ok if it shows up in the console");
Expand All @@ -250,15 +258,6 @@ describe("progress", function () {
deferred.notify();
deferred.resolve();

// In Node, swallow the eventually-thrown error.
function uncaughtExceptionHandler() { }
if (typeof process === "object") {
process.on("uncaughtException", uncaughtExceptionHandler);
promise.fin(function () {
process.removeListener("uncaughtException", uncaughtExceptionHandler);
});
}

return promise;
});

Expand Down Expand Up @@ -406,7 +405,7 @@ describe("progress", function () {
deferred.promise,
function () {
expect(progressed).toBe(true);
expect(progressContext).toBe(undefined);
expect(progressContext).toBe(STRICT_MODE_CAPABLE ? undefined : global);
},
function () {
expect(true).toBe(false);
Expand Down Expand Up @@ -646,10 +645,16 @@ describe("promises for objects", function () {

describe("keys", function () {

function Klass (a, b) {
this.a = a;
this.b = b;
}
Klass.prototype.notOwn = 1;

it("fulfills a promise", function () {
return Q.keys({a: 10, b: 20})
return Q.keys(new Klass(10, 20))
.then(function (keys) {
expect(keys).toEqual(['a', 'b']);
expect(keys.sort()).toEqual(['a', 'b']);
});
});

Expand Down Expand Up @@ -2080,4 +2085,3 @@ describe("possible regressions", function () {
});

});

0 comments on commit e3a927d

Please sign in to comment.