1
\$\begingroup\$

I am trying to hack together a simple promise implementation.

Is the following approach of maintaining a single async call and linking nested promises dynamically using their then method a viable approach?

const PromiseStatus = {
    pending: 'pending',
    fulfilled: 'fulfilled',
    rejected: 'rejected',
};
const DEFAULT_ERR = 'An unhandled exception occurred in Promise...';
var id = 0;
var scheduleId;

function Promise(executor) {
    
    var p, thens = [], catchCb = err=>console.error(DEFAULT_ERR, err), result;

    try {
        p = {
            id: id++,
            then,
            ['catch']: catchh, // 'catch' is reserved
        };

        p['__isSettled__'] = false;
        p['__PromiseStatus__'] = PromiseStatus.pending;
        p['__PromiseValue__'] = undefined;
        executor((...args) => schedule(resolve, ...args), reject);
        return p;

        function then(cb) {
            thens.push(value => thenCb(cb, value));
            return p;

            function thenCb(cb, value) {
                result = cb ? cb(value) : value;

                // Non-promise results...
                if (!isPromise(result)) {

                    if(!thens.length) {
                        p['__isSettled__'] = true;
                        p['__PromiseValue__'] = result;
                        p['__PromiseStatus__'] = PromiseStatus.fulfilled;
                        return p;
                    }

                    return thens.shift()(result);
                }

                // Promise results...
                if ((p['__isSettled__'] && !thens.length)) {
                    p['__PromiseValue__'] = result;
                    p['__PromiseStatus__'] = PromiseStatus.fulfilled;
                    return p;
                }
               
                // If the result Promise is fulfilled, use its value
                if(result.__PromiseStatus__ === PromiseStatus.fulfilled) {
                    return result.__PromiseValue__;
                }

                // "Bind" the Promise to the sub-promise
                p['__isSettled__'] = true;
                result.then(result => { 
                    return thenCb(undefined, result); 
                });
                return p;
            }
        }
        function catchh(cb) {
            catchCb = cb;
            return p;
        }
        function resolve(value) {
            try {
                return thens.shift()(value);
            } catch (err) {
                reject(err);
            }
        }
        function reject(err) {
            catchCb(err);
        }
        
    } catch (err) {
        p['__PromiseValue__'] = err;
        setTimeout(()=>catchh(err));
    }
}

function isPromise(o) {
    return o && o.then;
}

function schedule(fn, ...args) {
    clearTimeout(scheduleId);
    scheduleId = setTimeout(()=>fn(...args));
}

var p = new Promise(resolve=> {
    resolve('this is the result of a0');
})
.then(result=> {
    return new Promise(resolve=> { 
        resolve('this is the result of b0');
     })
     .then(result => { 
        return new Promise(resolve => { 
            resolve('this is the result of c0');
        });
     });
})
.then(result=> {
    console.log('final result is: \'', result, '\'');
return result;
}).catch(err=>{
    console.log('error: ', err);
});

\$\endgroup\$
  • \$\begingroup\$ Did you write this according to the specification? \$\endgroup\$ – Joseph Apr 25 '17 at 15:59
  • \$\begingroup\$ No. Actually, I know it does not meet the A+ specification (although at the time of writing the intention was to develop it in that direction). What I have presented is code showing "the direction of development". I wanted to validate the approach wrt asynchronicity and promise chaining in particular. Subsequent to posting @Bergi informed me of the failure to accommodate branching (something I was unaware of as a requirement). \$\endgroup\$ – 52d6c6af Apr 25 '17 at 16:10
  • \$\begingroup\$ Further to the above, after Bergi's comment on SO I know it is not viable as an Promises A+ standard implementation, but I am leaving it open here in case someone can contribute additional criticism. \$\endgroup\$ – 52d6c6af Apr 26 '17 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.