Я построил функцию, которая выполняет итерацию через Generator, содержащий как синхронный код, так и Promises:
module.exports = {
    isPromise (value) {
            return typeof value === 'object' && value !== null && 'then' in value;
        },
    runGen (generatorFunc, startValue) {
            let that = this,
                i = 0;
            function *iterator(resolve, reject) {
                let runGeneratorFunc = generatorFunc(startValue),
                    yieldedOut = {done: false},
                    yieldIn;
                while (!yieldedOut.done) {
                    console.log(i++, 'Ready for next iteration');
                    if (that.isPromise(yieldedOut.value)) {
                        console.log(i++, 'Pass promise to KeepIterating');
                        yieldIn = yield yieldedOut.value;
                        console.log(i++, 'Received value from promise');
                        if(yieldIn instanceof Error){
                            console.log(i++, 'Value was instance of Error');
                            try {
                                yieldedOut = runGeneratorFunc.throw(yieldIn)
                            }
                            catch(err){
                                console.log(i++, 'Throw Error');
                                throw(yieldIn);
                            }
                        } else {
                            yieldedOut = runGeneratorFunc.next(yieldIn);
                        }
                    } else {
                        try {
                            yieldIn = yieldedOut.value;
                            yieldedOut = runGeneratorFunc.next(yieldIn);
                        }
                        catch(err) {
                            runGeneratorFunc.throw(err);
                            reject(err);
                        }
                    }
                }
                resolve(yieldedOut.value);
            }
            return new Promise(function (resolve, reject) {
                var runIterator = iterator(resolve, reject);
                (function keepIterating(yieldIn) {
                    let yieldedOutPromise = runIterator.next(yieldIn);
                    if (!yieldedOutPromise.done) {
                        yieldedOutPromise.value.then(function (fulfilledValue) {
                            console.log('never gets here');
                            keepIterating(fulfilledValue);
                        });
                        yieldedOutPromise.value.catch(function (err) {
                            console.log(i++, 'Rejected promise catched');
                            if (err instanceof Error) {
                                try {
                                    console.log(i++, 'Rejected promise is instance of Error');
                                    let yieldedOut = runIterator.next(err);
                                    keepIterating(yieldedOut);
                                }
                                catch (err) {
                                    console.log(i++, 'Error propagated back out');
                                    yieldedOutPromise.value.catch(() => {})
                                    reject(err);
                                }
                            } else {
                                try {
                                    let yieldedOut = runIterator.next(new Error(err));
                                    keepIterating(yieldedOut);
                                }
                                catch (err) {
                                    reject(err);
                                }
                            }
                        })
                    }
                })();
            });
        }
    }
Теперь, когда я импортирую и запускаю его с помощью этого кода:
const md = require('./module');
function* dummy () {
    yield Promise.reject(new Error('error1'));
}
md.runGen(dummy)
.catch(err => {
    console.log(9, 'Finished!');
})
Я запустил это на консоль:
0 'Ready for next iteration'
1 'Ready for next iteration'
2 'Promise yielded out'
3 'Rejected promise handled'
4 'Rejected promise instance of Error'
5 'Ready to handle promise value'
6 'Value was instance of Error'
7 'Throw Error'
8 'Error propagated back out'
9 'Finished!'
(node:9904) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: error1
(node:9904) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Это все, как ожидалось, за исключением предупреждения о UnhandledPromiseRejectionWarning. Я смущен тем, почему я получаю это предупреждение, поскольку отклоненный Promise обрабатывается в коде, насколько я могу судить.
Что я пропускаю?
