I am a newbie to JS and I am trying to understand how Promise should work under the hood. Here is a custom implementation that looks reasonably good to me:
class MyPromise {
    constructor(executor) {
        this._resolutionQueue = [];
        this._rejectionQueue = [];
        this._state = 'pending';
        this._value;
        this._rejectionReason;
        try {
            executor(this._resolve.bind(this), this._reject.bind(this));
        } catch (e) {
            this._reject(e);
        }
    }
    _runRejectionHandlers() {
        while(this._rejectionQueue.length > 0) {
            var rejection = this._rejectionQueue.shift();
            try {
                var returnValue = rejection.handler(this._rejectionReason);
            } catch(e) {
                rejection.promise._reject(e);
            }
            if (returnValue && returnValue instanceof MyPromise) {
                returnValue.then(function (v) {
                    rejection.promise._resolve(v);
                }).catch(function (e) {
                    rejection.promise._reject(e);
                });
            } else {
                rejection.promise._resolve(returnValue);
            }
        }
    }
    _runResolutionHandlers() {
        while(this._resolutionQueue.length > 0) {
            var resolution = this._resolutionQueue.shift();
            try {
                var returnValue = resolution.handler(this._value);
            } catch(e) {
                resolution.promise._reject(e);
            }
            if (returnValue && returnValue instanceof MyPromise) {
                returnValue.then(function (v) {
                    resolution.promise._resolve(v);
                }).catch(function (e) {
                    resolution.promise._reject(e);
                });
            } else {
                resolution.promise._resolve(returnValue);
            }
        }
    }
    _reject(reason) {
        if (this._state === 'pending') {
            this._rejectionReason = reason;
            this._state = 'rejected';
            this._runRejectionHandlers();
            while(this._resolutionQueue.length > 0) {
                var resolution = this._resolutionQueue.shift();
                resolution.promise._reject(this._rejectionReason);
            }
        }
    }
    _resolve(value) {
        if (this._state === 'pending') {
            this._value = value;
            this._state = 'resolved';
            this._runResolutionHandlers();
        }
    }
    then(resolutionHandler, rejectionHandler) {
        var newPromise = new MyPromise(function () {});
        this._resolutionQueue.push({
            handler: resolutionHandler,
            promise: newPromise
        });
        if (typeof rejectionHandler === 'function') {
            this._rejectionQueue.push({
                handler: rejectionHandler,
                promise: newPromise
            });
        }
        if (this._state === 'resolved') {
            this._runResolutionHandlers();
        }
        if (this._state === 'rejected') {
            newPromise._reject(this._rejectionReason);
        }
        return newPromise;
    }
    catch(rejectionHandler) {
        var newPromise = new MyPromise(function () {});
        this._rejectionQueue.push({
            handler: rejectionHandler,
            promise: newPromise
        });
        if (this._state === 'rejected') {
            this._runRejectionHandlers();
        }
        return newPromise;
    }
}
module.exports = MyPromise;
As you see, this implementation has nothing to do with multi-threading itself, it's just coded in pure javascript without using any WebAPIs. Also, people say the built-in Promise is implemented without multi-threading in StackOverflow.
This MyPromise just work fine for most cases. However, MyPromise doesn't work the same as the built-in Promise in some cases and 'why?' is my question.
Here is the problematic code snippet:
new MyPromise((resolve, reject) => {
    console.log("first promise");
    resolve(1);
}).then((res) => {
    console.log("it's in then");
    return res+1;
}); console.log("it's in the end");
Executing the code spits out "first promise" -> "it's in then" -> "It's in the end", However,
new Promise((resolve, reject) => {
    console.log("first promise");
    resolve(1);
}).then((res) => {
    console.log("it's in then");
    return res+1;
}); console.log("it's in the end");
On the other hand, this spits out "first promise" -> "it's in the end" -> "it's in then"
The behavior of the builtin Promise doesn't look right unless the 'then' method implementation is fundamentally different from 'MyPromise.then'. Even taking 'task queue' and 'event loop' into account, I don't see a good explanation on why the difference.
I thought 'new Promise(f1).then(f2).then(f3);f4()' must be executed in the order of f1, f2, f3 and then f4, in a series, unless they include WebAPIs like setTimeout or $Ajax inside. But my little experiment doesn't say so, f1, f4, f2, ... you got the idea.
Is the 'then' method based upon some worker thread or something? I am totally lost.
Please shed some light on me. Thanks.