Jas Jas - 11 months ago 52
Javascript Question

Why would setTimeout def.reject code not run if the sendToSocket succeeds?

Why would

code not run if the sendToSocket succeeds?

this.send = function(type, body) {
var def = Promise.defer();
setTimeout(function() { // if the send sendToSocket Succeeds how does nodejs/javascript know not to run the timeout code after 10 seconds?
def.reject(new Error("timeout"));
}, 10000);

return def.promise;

Answer Source

As the comment said, a Promise's state may only be changed once, from pending to either fulfilled or rejected. Once the promise had been fulfilled, the rejection will be ignored.

In addition, it's considered better form to not use Promise.defer() and instead use the new Promise constructor:

return new Promise(function(resolve, reject) {
    sendToSocket({...}); // call resolve() here
    setTimeout(function() { reject(new Error("timeout")); }, 10000)

You'll notice that there's no try/catch here, that's because inside the Promise constructor, any thrown exception is automatically converted to a rejection for you.

Another thing I would do, is separate the method from the timeout, something like this:

function withTimeout(delay, fn) {
    return function() {
        return Promise.race([ // race between...
            // Promise that rejects after "delay" ms
            new Promise(function(resolve, reject) {
                setTimeout(function() { reject(new Error("timeout")); }, delay);
            }), // and...
            // Promise that actually does the action

            // The call to `Promise.resolve()` is to ensure we get a Promise
            // even if the function doesn't return one.
            Promise.resolve(fn.apply(null, arguments))

this.send = function() {
    return new Promise(function(resolve, reject) {
        sendToSocket({...}); // call resolve here, or reject on error.
                             // thrown errors will be converted anyway

this.sendWithTimeout = withTimeout(10000, this.send.bind(this));

Calling withTimeout will return a new function, that returns a Promise with the timeout option.

Promise.race() returns a Promise that resolves (or rejects) when the first Promise out of the passed array of Promises resolves or rejects. We're racing between the actual promise returned from this.send() and a promise that would reject on timeout.

This means that your this.send() function only deals with actually sending. The timeout is a detail you add via abstraction.