Git Product home page Git Product logo

q's Introduction

Note

Please consider using JavaScript promises instead of Q. Native promises are faster, have better tooling support and are the future.

When work on Q began, promises were an academic novelty in JavaScript, unlikely to be adopted much less popular, though obviously full of…promise. Callbacks dominated the landscape. Q aimed to introduce a technology to JavaScript that had been proven and vetted in languages like E and C♯. With four years of incubation, evangelism, education, and feedback, promises became part of the language. Every modern browser contains a built-in Promise implementation. Being able to influence the internet and working on a library used by millions of codebases was an exciting and humbling experience.

Q isn't going anywhere. The code is still here and bugs will be fixed but further development has been unnecessary for many years. We encourage you to read the code and the explainers to glimpse into the history of the internet.

Q

Build Status CDNJS

Q logo

If a function cannot return a value or throw an exception without blocking, it can return a promise instead. A promise is an object that represents the return value or the thrown exception that the function may eventually provide. A promise can also be used as a proxy for a remote object to overcome latency.

On the first pass, promises can mitigate the “Pyramid of Doom”: the situation where code marches to the right faster than it marches forward.

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});

With a promise library, you can flatten the pyramid.

Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
    // Do something with value4
})
.catch(function (error) {
    // Handle any error from all above steps
})
.done();

With this approach, you also get implicit error propagation, just like try, catch, and finally. An error in promisedStep1 will flow all the way to the catch function, where it’s caught and handled. (Here promisedStepN is a version of stepN that returns a promise.)

The callback approach is called an “inversion of control”. A function that accepts a callback instead of a return value is saying, “Don’t call me, I’ll call you.”. Promises un-invert the inversion, cleanly separating the input arguments from control flow arguments. This simplifies the use and creation of API’s, particularly variadic, rest and spread arguments.

Getting Started

The Q module can be loaded as:

  • A <script> tag (creating a Q global variable): ~2.5 KB minified and gzipped.
  • A Node.js and CommonJS module, available in npm as the q package
  • An AMD module
  • A component as microjs/q
  • Using bower as q#^1.4.1
  • Using NuGet as Q

Q can exchange promises with jQuery, Dojo, When.js, WinJS, and more.

Resources

Our wiki contains a number of useful resources, including:

  • A method-by-method Q API reference.
  • A growing examples gallery, showing how Q can be used to make everything better. From XHR to database access to accessing the Flickr API, Q is there for you.
  • There are many libraries that produce and consume Q promises for everything from file system/database access or RPC to templating. For a list of some of the more popular ones, see Libraries.
  • If you want materials that introduce the promise concept generally, and the below tutorial isn't doing it for you, check out our collection of presentations, blog posts, and podcasts.
  • A guide for those coming from jQuery's $.Deferred.

We'd also love to have you join the Q-Continuum mailing list.

Tutorial

Promises have a then method, which you can use to get the eventual return value (fulfillment) or thrown exception (rejection).

promiseMeSomething()
.then(function (value) {
}, function (reason) {
});

If promiseMeSomething returns a promise that gets fulfilled later with a return value, the first function (the fulfillment handler) will be called with the value. However, if the promiseMeSomething function gets rejected later by a thrown exception, the second function (the rejection handler) will be called with the exception.

Note that resolution of a promise is always asynchronous: that is, the fulfillment or rejection handler will always be called in the next turn of the event loop (i.e. process.nextTick in Node). This gives you a nice guarantee when mentally tracing the flow of your code, namely that then will always return before either handler is executed.

In this tutorial, we begin with how to consume and work with promises. We'll talk about how to create them, and thus create functions like promiseMeSomething that return promises, below.

Propagation

The then method returns a promise, which in this example, I’m assigning to outputPromise.

var outputPromise = getInputPromise()
.then(function (input) {
}, function (reason) {
});

The outputPromise variable becomes a new promise for the return value of either handler. Since a function can only either return a value or throw an exception, only one handler will ever be called and it will be responsible for resolving outputPromise.

  • If you return a value in a handler, outputPromise will get fulfilled.

  • If you throw an exception in a handler, outputPromise will get rejected.

  • If you return a promise in a handler, outputPromise will “become” that promise. Being able to become a new promise is useful for managing delays, combining results, or recovering from errors.

If the getInputPromise() promise gets rejected and you omit the rejection handler, the error will go to outputPromise:

var outputPromise = getInputPromise()
.then(function (value) {
});

If the input promise gets fulfilled and you omit the fulfillment handler, the value will go to outputPromise:

var outputPromise = getInputPromise()
.then(null, function (error) {
});

Q promises provide a fail shorthand for then when you are only interested in handling the error:

var outputPromise = getInputPromise()
.fail(function (error) {
});

If you are writing JavaScript for modern engines only or using CoffeeScript, you may use catch instead of fail.

Promises also have a fin function that is like a finally clause. The final handler gets called, with no arguments, when the promise returned by getInputPromise() either returns a value or throws an error. The value returned or error thrown by getInputPromise() passes directly to outputPromise unless the final handler fails, and 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
  • If the handler throws an error, the error passes to outputPromise
  • If the handler returns a promise, outputPromise gets postponed. The eventual value or error has the same effect as an immediate return value or thrown error: a value would be ignored, an error would be forwarded.

If you are writing JavaScript for modern engines only or using CoffeeScript, you may use finally instead of fin.

Chaining

There are two ways to chain promises. You can chain promises either inside or outside handlers. The next two examples are equivalent.

return getUsername()
.then(function (username) {
    return getUser(username)
    .then(function (user) {
        // if we get here without an error,
        // the value returned here
        // or the exception thrown here
        // resolves the promise returned
        // by the first line
    })
});
return getUsername()
.then(function (username) {
    return getUser(username);
})
.then(function (user) {
    // if we get here without an error,
    // the value returned here
    // 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 need to capture multiple input values in your closure.

function authenticate() {
    return getUsername()
    .then(function (username) {
        return getUser(username);
    })
    // chained because we will not need the user name in the next event
    .then(function (user) {
        return getPassword()
        // nested because we need both user and password next
        .then(function (password) {
            if (user.passwordHash !== hash(password)) {
                throw new Error("Can't authenticate");
            }
        });
    });
}

Combination

You can turn an array of promises into a promise for the whole, 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 replacement for then. The spread function “spreads” the values over the arguments of the fulfillment handler. The rejection handler will get called at the first sign of failure. That is, whichever of the received promises fails first gets handled by the rejection handler.

function eventualAdd(a, b) {
    return Q.spread([a, b], function (a, b) {
        return a + b;
    })
}

But spread calls all initially, so you can skip it in chains.

return getUsername()
.then(function (username) {
    return [username, getUser(username)];
})
.spread(function (username, user) {
});

The all function returns a promise for an array of values. When this promise is fulfilled, the array contains the fulfillment values of the original promises, in the same order as those promises. If one of the given promises is rejected, the returned promise is immediately rejected, not waiting for the rest of the batch. If you want to wait for all of the promises to either be fulfilled or rejected, you can use allSettled.

Q.allSettled(promises)
.then(function (results) {
    results.forEach(function (result) {
        if (result.state === "fulfilled") {
            var value = result.value;
        } else {
            var reason = result.reason;
        }
    });
});

The any function accepts an array of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected if all of the given promises are rejected.

Q.any(promises)
.then(function (first) {
    // Any of the promises was fulfilled.
}, function (error) {
    // All of the promises were rejected.
});

Sequences

If you have a number of promise-producing functions that need to be run sequentially, you can of course do so manually:

return foo(initialVal).then(bar).then(baz).then(qux);

However, if you want to run a dynamically constructed sequence of functions, you'll want something like this:

var funcs = [foo, bar, baz, qux];

var result = Q(initialVal);
funcs.forEach(function (f) {
    result = result.then(f);
});
return result;

You can make this slightly more compact using reduce:

return funcs.reduce(function (soFar, f) {
    return soFar.then(f);
}, Q(initialVal));

Or, you could use the ultra-compact version:

return funcs.reduce(Q.when, Q(initialVal));

Handling Errors

One sometimes-unintuitive aspect of promises is that if you throw an exception in the fulfillment handler, it will not be caught by the error handler.

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 try/catch. We are try-ing to execute foo(): the error handler represents a catch for foo(), while the fulfillment handler represents code that happens after the try/catch block. That code then needs its own try/catch block.

In terms of promises, this means chaining your rejection handler:

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:

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:

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

The End

When you get to the end of a chain of promises, you should either return the last promise or end the chain. Since handlers catch errors, it’s an unfortunate pattern that the exceptions can go unobserved.

So, either return it,

return foo()
.then(function () {
    return "bar";
});

Or, end it.

foo()
.then(function () {
    return "bar";
})
.done();

Ending a promise chain makes sure that, if an error doesn’t get handled before the end, it will get rethrown and reported.

This is a stopgap. We are exploring ways to make unhandled errors visible without any explicit handling.

The Beginning

Everything above assumes you get a promise from somewhere else. This is the common case. Every once in a while, you will need to create a promise from scratch.

Using Q.fcall

You can create a promise from a value using Q.fcall. This returns a promise for 10.

return Q.fcall(function () {
    return 10;
});

You can also use fcall to get a promise for an exception.

return Q.fcall(function () {
    throw new Error("Can't do it");
});

As the name implies, fcall can call functions, or even promised functions. This uses the eventualAdd function above to add two numbers.

return Q.fcall(eventualAdd, 2, 2);

Using Deferreds

If you have to interface with asynchronous functions that are callback-based instead of promise-based, Q provides a few shortcuts (like Q.nfcall and friends). But much of the time, the solution will be to use deferreds.

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
    if (error) {
        deferred.reject(new Error(error));
    } else {
        deferred.resolve(text);
    }
});
return deferred.promise;

Note that a deferred can be resolved with a value or a promise. The reject function is a shorthand for resolving with a rejected promise.

// this:
deferred.reject(new Error("Can't do it"));

// is shorthand for:
var rejection = Q.fcall(function () {
    throw new Error("Can't do it");
});
deferred.resolve(rejection);

This is a simplified implementation of Q.delay.

function delay(ms) {
    var deferred = Q.defer();
    setTimeout(deferred.resolve, ms);
    return deferred.promise;
}

This is a simplified implementation of Q.timeout

function timeout(promise, ms) {
    var deferred = Q.defer();
    Q.when(promise, deferred.resolve);
    delay(ms).then(function () {
        deferred.reject(new Error("Timed out"));
    });
    return deferred.promise;
}

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 implementation would be in order in practice.

function requestOkText(url) {
    var request = new XMLHttpRequest();
    var deferred = Q.defer();

    request.open("GET", url, true);
    request.onload = onload;
    request.onerror = onerror;
    request.onprogress = onprogress;
    request.send();

    function onload() {
        if (request.status === 200) {
            deferred.resolve(request.responseText);
        } else {
            deferred.reject(new Error("Status code was " + request.status));
        }
    }

    function onerror() {
        deferred.reject(new Error("Can't XHR " + JSON.stringify(url)));
    }

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

    return deferred.promise;
}

Below is an example of how to use this requestOkText function:

requestOkText("http://localhost:3000")
.then(function (responseText) {
    // If the HTTP response returns 200 OK, log the response text.
    console.log(responseText);
}, function (error) {
    // If there's an error or a non-200 status code, log the error.
    console.error(error);
}, function (progress) {
    // Log the progress as it comes in.
    console.log("Request progress: " + Math.round(progress * 100) + "%");
});

Using Q.Promise

This is an alternative promise-creation API that has the same power as the deferred concept, but without introducing another conceptual entity.

Rewriting the requestOkText example above using Q.Promise:

function requestOkText(url) {
    return Q.Promise(function(resolve, reject, notify) {
        var request = new XMLHttpRequest();

        request.open("GET", url, true);
        request.onload = onload;
        request.onerror = onerror;
        request.onprogress = onprogress;
        request.send();

        function onload() {
            if (request.status === 200) {
                resolve(request.responseText);
            } else {
                reject(new Error("Status code was " + request.status));
            }
        }

        function onerror() {
            reject(new Error("Can't XHR " + JSON.stringify(url)));
        }

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

If requestOkText were to throw an exception, the returned promise would be rejected with that thrown exception as the rejection reason.

The Middle

If you are using a function that may return a promise, but just might return a value if it doesn’t need to defer, you can use the “static” methods of the Q library.

The when function is the static equivalent for then.

return Q.when(valueOrPromise, function (value) {
}, function (error) {
});

All of the other methods on a promise have static analogs with the same name.

The following are equivalent:

return Q.all([a, b]);
return Q.fcall(function () {
    return [a, b];
})
.all();

When working with promises provided by other libraries, you should convert it to a Q promise. Not all promise libraries make the same guarantees as Q and certainly don’t provide all of the same methods. Most libraries only provide a partially functional then method. This thankfully is all we need to turn them into vibrant Q promises.

return Q($.ajax(...))
.then(function () {
});

If there is any chance that the promise you receive is not a Q promise as provided by your library, you should wrap it using a Q function. You can even use Q.invoke as a shorthand.

return Q.invoke($, 'ajax', ...)
.then(function () {
});

Over the Wire

A promise can serve as a proxy for another object, even a remote object. There are methods that allow you to optimistically manipulate properties or call functions. All of these interactions return promises, so they can be chained.

direct manipulation         using a promise as a proxy
--------------------------  -------------------------------
value.foo                   promise.get("foo")
value.foo = value           promise.put("foo", value)
delete value.foo            promise.del("foo")
value.foo(...args)          promise.post("foo", [args])
value.foo(...args)          promise.invoke("foo", ...args)
value(...args)              promise.fapply([args])
value(...args)              promise.fcall(...args)

If the promise is a proxy for a remote object, you can shave round-trips by using these functions instead of then. To take advantage of promises for remote objects, check out Q-Connection.

Even in the case of non-remote objects, these methods can be used as shorthand for particularly-simple fulfillment handlers. For example, you can replace

return Q.fcall(function () {
    return [{ foo: "bar" }, { foo: "baz" }];
})
.then(function (value) {
    return value[0].foo;
});

with

return Q.fcall(function () {
    return [{ foo: "bar" }, { foo: "baz" }];
})
.get(0)
.get("foo");

Adapting Node

If you're working with functions that make use of the Node.js callback pattern, where callbacks are in the form of function(err, result), Q provides a few useful utility functions for converting between them. The most straightforward are probably Q.nfcall and Q.nfapply ("Node function call/apply") for calling Node.js-style functions and getting back a promise:

return Q.nfcall(FS.readFile, "foo.txt", "utf-8");
return Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]);

If you are working with methods, instead of simple functions, you can easily run in to the usual problems where passing a method to another function—like Q.nfcall—"un-binds" the method from its owner. To avoid this, you can either use Function.prototype.bind or some nice shortcut methods we provide:

return Q.ninvoke(redisClient, "get", "user:1:id");
return Q.npost(redisClient, "get", ["user:1:id"]);

You can also create reusable wrappers with Q.denodeify or Q.nbind:

var readFile = Q.denodeify(FS.readFile);
return readFile("foo.txt", "utf-8");

var redisClientGet = Q.nbind(redisClient.get, redisClient);
return redisClientGet("user:1:id");

Finally, if you're working with raw deferred objects, there is a makeNodeResolver method on deferreds that can be handy:

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
return deferred.promise;

Long Stack Traces

Q comes with optional support for “long stack traces,” wherein the stack property of Error rejection reasons is rewritten to be traced along asynchronous jumps instead of stopping at the most recent one. As an example:

function theDepthsOfMyProgram() {
  Q.delay(100).done(function explode() {
    throw new Error("boo!");
  });
}

theDepthsOfMyProgram();

usually would give a rather unhelpful stack trace looking something like

Error: boo!
    at explode (/path/to/test.js:3:11)
    at _fulfilled (/path/to/test.js:q:54)
    at resolvedValue.promiseDispatch.done (/path/to/q.js:823:30)
    at makePromise.promise.promiseDispatch (/path/to/q.js:496:13)
    at pending (/path/to/q.js:397:39)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

But, if you turn this feature on by setting

Q.longStackSupport = true;

then the above code gives a nice stack trace to the tune of

Error: boo!
    at explode (/path/to/test.js:3:11)
From previous event:
    at theDepthsOfMyProgram (/path/to/test.js:2:16)
    at Object.<anonymous> (/path/to/test.js:7:1)

Note how you can see the function that triggered the async operation in the stack trace! This is very helpful for debugging, as otherwise you end up getting only the first line, plus a bunch of Q internals, with no sign of where the operation started.

In node.js, this feature can also be enabled through the Q_DEBUG environment variable:

Q_DEBUG=1 node server.js

This will enable long stack support in every instance of Q.

This feature does come with somewhat-serious performance and memory overhead, however. If you're working with lots of promises, or trying to scale a server to many users, you should probably keep it off. But in development, go for it!

Tests

You can view the results of the Q test suite in your browser!

License

Copyright 2009–2017 Kristopher Michael Kowal and contributors MIT License (enclosed)

q's People

Contributors

amzotti avatar anton-rudeshko avatar benjamingr avatar benjamn avatar davidpadbury avatar dfilatov avatar domenic avatar ef4 avatar erights avatar erikvold avatar forbeslindesay avatar gozala avatar ivanetchart avatar jbunton-atlassian avatar jrburke avatar kahnvex avatar kriskowal avatar lekoaf avatar mariotsi avatar mdlavin avatar rictic avatar rkatic avatar ruffle1986 avatar ryanwitt avatar slaks avatar terinjokes avatar timruffles avatar vilicvane avatar wizardwerdna avatar wmertens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

q's Issues

Node tests causing the runner to hang in browsers without bind

I tracked down the hangs. It happens because nbind uses callback.bind.apply(callback, args), and some browsers don't have bind.

This isn't a big deal. But we should fix it. First off, the test runner needs timeout support so this doesn't confuse us again, so I'll try adding that. Although, why isn't it just failing? A bit strange. Will investigate.

The question for discussion is, do we want to support nbind et al. in old browsers, or not? I can vaguely see the argument for someone wanting to use these methods in non-Node contexts. But they are named specifically for Node (where bind is always available). So we could either:

  1. Modify nbind to not use Function.prototype.bind, thus allowing nbind et al. to be used in old browsers.
  2. Wrap that section of tests in a if (Function.prototype.bind) or similar, so that they don't even run in old browsers.

README: perhaps illustrate the problem and why q is the solution

Great new README! It would have really helped me dive into q easier. I'm wondering if it makes sense to give a quick intro into the problem q helps solve. Here is a shot at it, but probably needs a bit of massaging, feel free to disregard too if I got the overall message wrong.


If a function cannot return a value or throw an exception without blocking, it can return a promise instead. A promise is an object that represents the return value or the thrown exception that the function may eventually provide. A promise can also be used as a proxy for a remote object to overcome latency.

So, instead of writing code like this:

asyncCall1(function (value1) {
    asyncCall2(value1, function(value2) {
        asynCall3(value2, function(value3) {
            asynCall4(value3, function(value4) {
                //Do something with value4
            });
        });
    });
});

You can write code like so:

q.call(asyncCall1)
    .then(asyncCall2)
    .then(asyncCall3)
    .then(asynCall4)
    .then(function(value4) {
        //Do something with value4
    })
    .end();

with the added benefit of being able to let errors propagate to top level error handlers. Focus more on your code logic and less on handling function callbacks.


node and ncall functions should handle promises as an arguments

True promise-wrappers for callback-style functions should also handle promises as an arguments.
Example below should work, but breaks with an error:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Bad argument
    at Object.open (fs.js:224:11)
    at new <anonymous> (fs.js:1056:6)
    at Object.createReadStream (fs.js:1010:10)
    at Object.readFile (fs.js:78:23)
    at Object.apply (/usr/local/lib/node_modules/q/q.js:395:27)
    at Promise.promiseSend (/usr/local/lib/node_modules/q/q.js:243:41)
    at Array.0 (/usr/local/lib/node_modules/q/q.js:632:28)
    at EventEmitter._tickCallback (node.js:192:40)

Example:

var Q = require('q'),
    FS = require('fs');

Q.ncall(FS.readFile, FS, Q.ref(__filename))
.then(function(c) {
    console.log(c);
})
.end();

Need a way to inject the `nextTick` implementation

I am using Q in mozilla addon sdk which parses for static requires in order to authorize loading a module dependency from a module.

Problem is serverSideRequire("event-queue") which is not detected (as indended).

The best solution that does not interfere with the current requirements seems to be injecting the nextTick implementation.

Could we add something like Q.nextTick which I can set externally and use that over fallbacks?

Missing Q.join and Q.deep from 0.4.0

Hi Kris, I see that after util.js was merged into Q, the methods Q.join and Q.deep were completely removed.

Is it by purpose or will you reintroduce them soon? So far we must stick with 0.3.0 because of that.

Thanks for your great work, it is the best Promise library in JS!

examples folder is out of date

Not sure what you want to do with them, exactly, but currently it uses lots of nonexistant methods from a util module, something about a "view" experiment, etc.

Rename `Q.node` to `Q.nbind`

With the addition of Q.bind, and all the recent discussion of Q.call, I'm feeling like Q.node really should be Q.nbind. Thoughts?

Do we need/want a Q.napply? I haven't found a use case for it, ever, but it would complete the set.

console.log seems to be problematic in IE9

IE9 (no idea about other versions) seems to only define window.console if the developer tools are open. Q calls console.log and thus won't (fully) work in IE9. Everything past the call to console.log presumably doesn't get executed, but it's hard to verify, given that this is a Heisenbug. (Opening the dev tools will cause Q to work fine.)

There's only one call to console.log in q.js, but I didn't understand its purpose well enough to just create a pull request. I would suggest wrapping console.log in an if (window.console !== undefined) or simply removing the call.

FYI, a workaround is to include this line of script above the script tag pulling in q.js: if (window.console === undefined) window.console = { log: function () { } };

Throw in promise-fulfillment swallows exception

<html>
<head>
<script src="../../lib/q/q.js"></script>
<script>

// Accept a promise for load, and report the success or failure of the load
function foo(loaded) {
 return Q.when(
   loaded, 
   function glory(loaded){
     // Ooops the processing of success path fails!
     throw new Error("You lose");
     console.log("We have ", loaded);
   }, 
   function fail(err) {
     console.error("We have "+err);
   }
 );
};

// Create a promise for a load
function promiseLoaded() {
  var defer = Q.defer();
  window.addEventListener(
    'load', 
    function(event) {
      defer.resolve("success");
    }, 
    false
  );
  return defer.promise;
}

function main() {
  // foo returns a promise, but we don't look at the return so we lose.
  foo(promiseLoaded());
}

main();
</script>
</head>
<body>
<h1>Bad developer ergonomics: throw in promise fulfillment swallows exception</h1>
<p>May be related to <a href="https://github.com/kriskowal/q/issues/23">Issue 23 on github q</a>
</body>
</html>

Wrapping everything in nextTick() should be optional

Calling nextTick is good for letting other parts of application to execute, but it may cause nonobvious problems when dealing with streams in node.js.

For example, creating ReadStream and then using it after resolve will end up in skipping some "data" events on it, because we skipped one event-loop tick.

README / Docs out of date

There have been major API changes that haven't been reflected in the README.
I wasted a couple hours this weekend trying to figure out what I was doing wrong.
I usually just RTFC, but the docs were just so good that I didn't think I needed to ;)
Oh well ^_^

Thanks!

Add .npmignore file

.npmignore keeps some stuff out of npm that is not needed when q is installed in a project.

By excluding things it makes it easier/lighter to commit node_modules with q into a source repo.

Here is one that may work for q:

design
examples
lib
test
CHANGES.md
VERSIONS.md
q-spec.html
q-spec.js
q.min.js
q.min.js.gz
ref_send.md

Q.deep resolves JS built-in objects as {}

This behaviour is rather unintuitive. Is this by design?

Here is an example:

Q.when(Q.deep(new Date()), function(ret) {
  console.log(ret);
});

===> {}

whereas

Q.when(new Date(), function(ret) {
  console.log(ret);
});

===> Sat, 29 Jan 2011 10:23:24 GMT

Support a "capping required" mode of operation; or allow reporting unheard rejections.

Although I try very hard to avoid letting success values or rejections fall on the floor, I keep screwing up, and it seems like Q could help make it more obvious when I am screwing up.

The defer() resolve() implementation knows when it is being resolved with no one around to hear because pending will be empty. I propose adding some kind of optional reporting in this case. This would allow my testing framework to both notice when:

  • an error occurs and no one is paying attention to the rejection when it pops out the top
  • a very dumb program logic bug has some code returning a promise but no one is actually hooked up

Obviously, there needs to be a way to actually "cap" the chain of promises. The current end() method does this in spirit, but I believe will still result in resolutions with an undefined value. (OTOH, undefined could just be made special in that it does not trigger the reporting logic.)

I recognize that there are two use-cases that would not be happy about this happening all the time:

  1. People more clever than me who don't want to have to cap everything because they don't screw up.
  2. Programming idioms where the "when" request registration with the promise does not happen nearly immediately and instead the promise is held onto for multiple ticks and registered with later. This may happen more frequently than I expect, even in Q-provided helpers.

The solution to both those problems is that this would be opt-in. Either you could provide a custom handler, or invoke "$Q.forBabies()" which would just throw, thereby relying on node's/the browser's built-in stuff.

Consider using `setImmediate` if available

global.setImmediate is a proposed-for-standardization version of Q.nextTick.

It does not seem to be winning the battle for the hearts and minds of spec editors (MDN says "is not expected to become standard"; negative comments from Hixie in a related bug). But, it does seem to be winning the hearts and minds of developers (blog post from Nicholas Zakas; dependencies from a reasonably-popular Knockout.js plugin; even a (closed) bug to use it in underscore.js). So it might get somewhere in the end, and Q's support could help push things in that direction.

Currently the only way to get it is through manually shimming it; the only browser to have it natively is IE9, and there it's hidden behind a prefix. So if we said var nextTick = global.setImmediate || (existing code), this would only work for people who have included a shim.

Still, this seems like a win. For shim users, it gives faster promises in non-MessageChannel-supporting browsers. It would also solve #44, by allowing users in the add-on SDK environment to do a quick shim like global.setImmediate = require("event-queue").enqueue.

What do you think?

Advertise minified/gzipped size

One of the most common questions I get when presenting on promises, and recommending Q, is "how big is this Q library you're telling me I need?" Putting something near the top of the readme (perhaps a tacky badge?) would probably be helpful for many.

Both when() callbacks can get triggered.

I'm not entirely sure if what I've run into is a bug in Q per se, or just weird behavior because I'm mis-using it, but in any case, I've constructed an example where both the resolved and rejected callbacks of a when will get called. My understanding is that only one or the other should ever get called.

All you need to do to get the bad behavior is define a custom promise which always responds to when() by returning a rejection, as opposed to calling the passed-in rejected function. See below.

My best guess is that this isn't the recommended way to write a when() though I would have also guessed that it should still work. BTW, I noticed that in the inner implementation, it doesn't count on rejected being passed in, but at the level of my example here, is it actually safe to assume that it's a real function?

Here's the code:

var Q = require("q");

function makePromiseCore() {
    function post(name, args) {
        return "hello";
    }

    function when(rejected) {
        return Q.reject(new Error("permanently unresolved"));
    }

    return {
        post: post,
        when: when
    };
}

function onResolved(value) {
    console.log("Resolved to:", value);
}

function onRejected(value) {
    console.log("Rejected as:", value);
}

var promise = Q.makePromise(makePromiseCore());
promise.when(onResolved, onRejected);

And here's a transcript of running it:

$ node ./weirdwhen.js 
Rejected as: [Error: permanently unresolved]
Resolved to: undefined

Thanks for your consideration. I'm generally quite enthused with this module!

feature request: deferred provides Node-style callback

I often find myself wrapping Node-style API methods in promises, and doing something like the following:

 var def = Q.defer();
 doSomething(a, b, function(err, result) {
    if (err) {
        def.reject(err);
    } else {
        def.resolve(result);
    }
 });
 return def.promise;

It would be great if I could do this instead:

var def = Q.defer();
doSomething(a, b, def.callback());
return def.promise;

Would that be possible?

Better method for returning from async generator functions

Wouldn't it be better if example 1 for async-generators could look like:

function test() {
    var generator = Q.async(function () {
        var ten = yield 10;
        console.log(ten, 10);
        var twenty = yield ten + 10;
        console.log(twenty, 20);
        var thirty = yield twenty + 10;
        console.log(thirty, 30);
        yield $return(thirty + 10);
    });
    Q.when(generator(), function (fourty) {
        console.log(fourty, 40);
    }, function (reason) {
        console.log("error", reason);
    });
}

To make this work you'd just need to include a function $return which returned an object with a known type and with the value attached. This could then be checked for in the async method instead of checking for the exception. Alternatively, if we must have the exception thrown, why not create a simple function which throws that exception, so as to hide some of the ugliness?

Opera Error

When running in Opera browser:

Error thrown at line 7, column 622 in <anonymous function: l>(a) in http://localhost:8080/workspace/www/q.min.js:
    B.port2.postMessage()
called from line 6, column 47 in g(a, b, d) in http://localhost:8080/workspace/www/q.min.js
called from line 6, column 882 in v(a) in http://localhost:8080/workspace/www/q.min.js

I know stack is not helpful :) Assuming you will test source in Opera ;)

Q.npost() and Q.ninvoke() pass wrong arguments to napply

There is an error in Q.npost() and Q.ninvoke(), they should pass object as a second argument to napply(), not name.

/**
 * Calls a method of a Node-style object that accepts a Node-style
 * callback with a given array of arguments, plus a provided callback.
 * @param object an object that has the named method
 * @param {String} name name of the method of object
 * @param {Array} args arguments to pass to the method; the callback
 * will be provided by Q and appended to these arguments.
 * @returns a promise for the value or error
 */
exports.npost = npost;
function npost(object, name, args) {
    return napply(object[name], object, args);
}

/**
 * Calls a method of a Node-style object that accepts a Node-style
 * callback, forwarding the given variadic arguments, plus a provided
 * callback argument.
 * @param object an object that has the named method
 * @param {String} name name of the method of object
 * @param ...args arguments to pass to the method; the callback will
 * be provided by Q and appended to these arguments.
 * @returns a promise for the value or error
 */
exports.ninvoke = ninvoke;
function ninvoke(object, name /*, ...args*/) {
    var args = array_slice(arguments, 2);
    return napply(object[name], object, args);
}

use process.nextTick on node instead of setTimeout

I have added "event-queue" package to the npm that wraps process.nextTick to the require('event-queue').enqueue. By adding it to the dependencies in package descriptor promises can take advantage of process.nextTick on node, which is much more efficient.

I'll create a pull request from this commit:
http://github.com/Gozala/q/commit/5aafc6bad5a4e858d2f0421937af41ae11a9a187

Since this changes dependencies property it will have to wait before
http://github.com/kriskowal/q/pull/1
is in

Function.prototype.qcall

Q.ncall is really clever. I’m not 100% sure, but it might warrant a Function.prototype.qcall, perhaps even an qfcall (without a parameter for this).

Before:

function expandUrl(shortUrl) {
    var deferred = Q.defer();
    return Q.ncall(request, null, {
        method: "HEAD",
        url: shortUrl,
        followAllRedirects: true
    }).get('request').get('href');
}

After:

function expandUrl(shortUrl) {
    return request.qfcall({
        method: "HEAD",
        url: shortUrl,
        followAllRedirects: true
    }).get('request').get('href');
}

Thus: Instant q-ification of all Node.js functions. Instead of qcall, one could also use the name nodecall (still short, somewhat more descriptive).

Add back in examples of array processing

I have an array of promisey functions, and I want to call them one after the other. What's a nice, concise way to do this?

The old README, under "Serial Join", had some nice exampes using Array.prototype.reduce and Q.wait. But Q.wait is dead, not that I knew what it really did in the first place.

So far the best I have is

var array = [fooAsync, barAsync];

return array.reduce(function (soFar, thisFuncAsync) {
    return soFar.then(thisFuncAsync);
}, Q.resolve());

But it feels weird having to pass in the empty Q.resolve.

Move most of the README to wiki pages

I think the API and Advanced API sections would be best as separate wiki pages, linked from the README.

I'm torn between keeping the beautiful new tutorial in the README or moving it to the wiki and having a really slimmed-down README.

Alternate name for deferred.node()

Alex Raschmeyer recommends that we reconsider the name of the node callback function.

http://www.2ality.com/2012/04/expand-urls.html

For what it’s worth, the callback could always be the same object and thus it would make sense for it to be a property rather than a function, but it would incur the cost of generate such a function for every deferred. That is why it is a function. Alternate approaches could simulate a property in some cases.

Browser test suite

We need a way to run tests in browsers to validate the releases. @Gozala’s CommonJS unit test suite work great in Node.

We must have a solution that works for both browsers and Node. I would accept a temporary solution that ports the tests to Jasmine or something. I would accept a solution that embeds a mini module loader to run the tests client-side.

Console hooks

Q should send messages to the console when promises are manipulated so that a monitor like a Causeway logger or Web Inspector view can be attached.

The corresponding console API is not defined. This is an idea to start the thinking process:

console.deferred(deferred);
console.resolved(promise);
console.fulfilled(promise);
console.rejected(promise);

Support for Promise.pipe is needed...

I did not see this in your library, so the following feature is critical:

Promise.pipe( function(result) { 
    .... 
    return value || promise; 
}); 

This feature supports promise chains, resolve() result transformations, resolve() rejections.

This is a HUGE missing feature. Please add to your library.

Add "some" handler

I have an issue when processing and array of promises. I need the ability to catch all the results on fin no mater if they fail or not and examine the results.

This is kind of an optimistic asynchronous execution. Since "all" fires fail if any of the promises fails I propose the addition of "some" handler. "some" could resemble all but would be something like this:

function some(promises) {
    return when(promises, function (promises) {
        var countDown = promises.length;
        if (countDown === 0)
            return resolve(promises);
        var deferred = defer();
        reduce.call(promises, function (undefined, promise, index) {
            fin(promise, function () {
                promises[index] = promise;
                if (--countDown === 0)
                    deferred.resolve(promises);
            })
        }, void 0);
        return deferred.promise;
    });
}

I would like your opinion before I issue a pull request.

Cheers,
utvara

Thoughts on Q.async

This is just a thought, feel free to disagree with me, but I'd just like to throw the idea out there.

I have a suspicion, that once yield is available in more environments (I'm currently writing a shim to compile it to ECMA5 based on the current standards) we'll see lots of methods that look like the following.

var sumOfStuff = Q.async(function(a,b,c,d,e,f,g,h){
    a = yield a;
    b = yield b;
    c = yield c;
    d = yield d;
    e = yield e;
    f = yield f;
    g = yield g;
    h = yield h;
    var other = yield someRemoteData({id:a});
    Q.return(other+b+c+d+e+f+g+h);
});

That is to say, lots of functions will begin by yielding on all their arguments, either one at a time, or using something like Q.all.

What might be preferable, would be to resolve all promises that are passed as arguments, before giving them to the function. The only down side, is that it prevents you from writing functions like:

var hash = Q.async(function(pass){
    var salt = getRandom();//computationally expensive
    Q.return(salt + yield pass);
});

Perhaps we could have some way of annotating the function as lazy but resolve all arguments by default?

Cancellation

Cancellation is tricky.

Mark Miller argues that we should not add cancellation at all. On the flip side, most people feel the need for it, including @domenic and @IgorMinar. If cancelation is a mistake, it is an oft-made mistake.

Consider a naïve cancelable promise.

function service() {
    // start work…
    var deferred = Q.defer(function cancel() {
        // …stop work
    });
    deferred.promise;
}

var promise = service();
clientA(promise);
clientB(promise);

There is a hazard in this case. Either clientA or clientB might call promise.cancel() and thus interfere with the other client’s progress. With your face close to the page, it looks like the problem is that we need a way to count how many services depend on the promise. From a higher perspective, cancelation is inherently hazard prone.

The philosophical reasoning behind banning cancelation outright is that a cancelable promise must necessarily have all of the power of a deferred, nullifying the (POLA) advantage of separating the promise part from the resolve part. Anyone with a cancelable can call cancel(), which is effectively equivalent to preemptively rejecting the promise (resolving the promise with a rejection).

So, Mark argues, if you want something to be cancelable, just return the whole deferred to make it clear that you’re granting both powers. “Similar things should either be very different or the same” — Mark Miller attributes this paraphrase to Alan Kay.

In this example, the promise can be cancelled by rejecting the deferred.

function delay(ms) {
    var handle = setTimeout(deferred.resolve, ms);
    var deferred = Q.defer();
    Q.catch(deferred.promise, function () {
        clearTimeout(handle);
    });
    deferred;
}

var deferred = service();
clientA(deferred);
clientB(deferred);

deferred.reject(new Error("Cancelled”));

This at least demonstrates the critical insight that, regardless of how cancelation looks, this is certainly how it should work. It does not inherently solve the problem of tracking how many parties remain interested in the result.

However, there is a story on graceful migration that this does not address. Expressing that you are no longer interested in a result is orthogonal to expressing that you are able to cancel work if no one is interested any longer in the result. I posit, it should be possible to go through either side of this extra effort independently. That is, a cancelable should have the same interface as a promise, albeit all the powers of a deferred, but also, all promises should have the interface of a cancelable, even if they do not provide that power. As such, it would be possible for a service provider to add cancelability to a promise before or after a service consumer adds support for proactively canceling promises that they no longer need.

Down this track of thought, promises would have a cancel() method which would be a NOOP. A cancelable would be a new type of object entirely, that has the interface of a promise and the powers of a deferred. A cancelable would have a functioning cancel() method. All of the promise-like methods of a cancelable would return new, normal promises, and cancelation would not implicitly propagate. Cancelables could be constructed from deferreds, like Q.cancelable(deferred).

The cancelable solution might not stick since it would obviate chaining. Each step of the promise chain would have to be replaced with an explicit mechanism for how to forward cancelation. We’d have to explore some code samples to see whether it would be worth dealing with, and whether we might find ways to make it easy to flag common policies.

For either approach, using a deferred or a cancelable, there is the independent problem of tracking how many parties are still interested in the result of a promise and actually canceling only when that drops to 0.

Ideally, we could involve the garbage collector since it does this work already. We could use a WeakRef, or any mechanism that notifies the application after an object has been garbage collected. We could use this mechanism to implicitly cancel any promise for which there are provably no observers. However, we do not live in a world with WeakRef, and such would only work if the promise library were to exist in a privileged context, possibly served to unprivileged contexts.

In the real world, we would have to do reference counting in application-space. One thought would be to add a fork() function to a cancelable. The cancelable could contain an internal counter of how many forks exist and each fork could decrement that number exactly once. When they drop to zero, the cancelable could commit to stopping work.

This should be an accurate summary of every discussion I’ve had on the topic as-yet. Please chime in.

Long (temporal) stack traces

I'd like to use this issue to document the well-known problem with Q stack traces, and as a place to discuss any progress I can make toward improving it. I'm currently investigating the V8 stack trace API as a possible help.


Consider the following code:

"use strict"; // 1

var Q = require("q"); // 3

function doXAsync() { // 5
    return Q.resolve(5); // 6
}

function doYAsync() { // 9
    return doXAsync().then(function () { // 10
        throw new Error("boo!"); // 11
    });
}

function doZAsync() { // 15
    return doYAsync(); // 16
}

doZAsync().end(); // 19

Currently this prints the following stack trace:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: boo!
    at c:\Users\Domenic\Programming\test\test.js:11:15
    at _fulfilled (c:\Users\Domenic\Programming\test\node_modules\q\q.js:542:32)
    at makePromise.promiseSend (c:\Users\Domenic\Programming\test\node_modules\q\q.js:257:37)
    at c:\Users\Domenic\Programming\test\node_modules\q\q.js:564:18
    at makePromise.promiseSend (c:\Users\Domenic\Programming\test\node_modules\q\q.js:257:37)
    at Array.0 (c:\Users\Domenic\Programming\test\node_modules\q\q.js:557:24)
    at EventEmitter._tickCallback (node.js:192:40)

Ideally it would print something more like

Error: boo!
    at c:\Users\Domenic\Programming\test\test.js:11:15
    at doYAsync (c:\Users\Domenic\Programming\test\test.js:10:xx)
    at doZAsync (c:\Users\Domenic\Programming\test\test.js:16:xx)
    at c:\Users\Domenic\Programming\test\test.js:19:xx

Agreed?

Question about recursive functions and how to use Q

Sorry if this is an simple question, I'm new to promises/futures.

I'm using the mongodb driver, and I need a recursive function to simulate joins on a table, the pseudocode woudl look like

function collectColumnNames(collectionName, columnNames )
{
foreach ( row in collection )
{
foreach ( column in row )
{
if ( column is lookupColumn ) collectColumnNames(column.name, columnNames );
else columnNames.push(column.name );
}
}
}

But of course because this is asynch I'm not getting all the column names.

How can I use Q to solve this problem ?

Thanks!
Charlie

append reduce attribute to some array in node

i have a array like [1,2,3],after i do invoke the resolve function like xx.resolve(the_array), the array data change to [1,2,3, reduce: [function...]]

i think the ploblem is occur by this code in q.js:

var reduce =
Array.prototype.reduce =
Array.prototype.reduce || function (callback, basis) {
for (var i = 0, ii = this.length; i < ii; i++) {
basis = callback(basis, this[i], i);
}
return basis;
};

the right way maybe this:

var reduce =
Array.prototype.reduce || (Array.prototype.reduce = function (callback, basis) {
for (var i = 0, ii = this.length; i < ii; i++) {
basis = callback(basis, this[i], i);
}
return basis;
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.