JSFiddle - React, Tailwind, and code Playground

HTML

<div id='output'></div>

JavaScript

function logit() {
    var dest = document.querySelector('#output');
    var div = document.createElement('div');
    div.textContent = Math.floor(new Date() / 1000) + ' ' +[].join.call(arguments, ' ');
    dest.appendChild(div);
}
function inSeries(array, fn) {
    var promises = [];
    array.reduce(function(ret, v) { 
        var promise = ret.then(fn.bind(null, v)).then(
            function(x) { return {state: "fulfilled", value: x};}, 
            function(e) { return {state: "rejected" , value: e};}
        );
        promises.push(promise);
        return promise;
    }, Promise.resolve());
    return Promise.all(promises);
}

var fn = function(v) {
    logit('begin', v.value);
    if (v.timeout) {
        return new Promise(function(resolve, reject) {
            window.setTimeout(function() {
                if (v.timeout < 0) {
                    logit('reject', v.value);
                    reject(v.value);
                }
                else {
                    logit('resolve', v.value);
                    resolve(v.value);
                }
            }, Math.abs(v.timeout));
        });
    }
    else {
        logit('return', v.value);
        return v.value;
    }
};
var test = {
    ka: { value: 'a', timeout: 6000 },
    kb: { value: 'b' }, // return
    kc: { value: 'c', timeout: 2000 },
    kd: { value: 'd', timeout: -2000 }, // reject
    ke: { value: 'e', timeout: 2000 },
    kf: { value: 'f', timeout: 2000 },
};
logit('begin');
inSeries(Object.keys(test).map(function(key) {
    return test[key];
}), fn).then(function(results) {
    logit('done');
    results.forEach(function(result) {
        logit(result.value + ' : ' + result.state);
    });
});