The difference is described at http://promisesaplus.com/ in accordance with the promise resolution process.
For the first return value:
2.3.3.4 If then not a function, keep the promise with x.
For the second:
2.3.2 If x is a promise, accept its state [3.4]:
2.3.2.2 If / when executing x, keep the promise with the same value.
We see that this is implemented by q.js. This is one possible implementation, but seems to explain the delay:
function coerce(promise) { var deferred = defer(); Q.nextTick(function () { try { promise.then(deferred.resolve, deferred.reject, deferred.notify); } catch (exception) { deferred.reject(exception); } }); return deferred.promise; }
When returning a promise from the then function, we have two separate promise objects: one that returns from the function passed to then , and one that returns from then . They must be connected together to resolve the first, allows the second. This is done using promise.then(deferred.resolve, ...)
The first delay comes from Q.nextTick . This performs the function in the next iteration of the event loop. There is some discussion in commenting on comments about why this is necessary.
Calling promise.then adds the extra delay of one iteration of the event loop. As required in the specification:
2.2.4 onFulfilled or onRejected should not be called until the execution context stack contains only platform code. [3.1].
The execution will look something like this:
p1.then with function containing 1.1.1 is called function containing 1.1.1 is queued p1.then with function containing 1.2 is called function containing 1.2 is queued Promise resolving to 30 is returned Q.nextTick function is queued ---------- 1.1.1 is printed p1.then with function containing 1.1.2 is called function containing 1.1.2 is queued 1.2 is printed Q.nextTick function is executed promise.then(deferred.resolve, ...) is queued ---------- 1.1.2 is printed p1.then with function containing 1.1.3 is called function containing 1.1.3 is queued promise.then(deferred.resolve, ...) is executed function containing val/2 is queued ---------- 1.1.3 is printed val/2 is printed