From 5c4da0db155d850bf03ceea9e136d587d190e9b1 Mon Sep 17 00:00:00 2001 From: kundol Date: Mon, 9 Dec 2024 14:51:41 +0900 Subject: [PATCH] closed #5251 --- lib/runnable.js | 96 +++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/lib/runnable.js b/lib/runnable.js index 98327bf5d9..87dc5c2ea9 100644 --- a/lib/runnable.js +++ b/lib/runnable.js @@ -347,46 +347,74 @@ Runnable.prototype.run = function (fn) { return; } - // sync or promise-returning - try { - callFn(this.fn); - } catch (err) { - errorWasHandled = true; - if (err instanceof Pending) { - return done(); - } else if (this.allowUncaught) { - throw err; - } - done(Runnable.toValueOrError(err)); - } + Promise.resolve() + .then(() => callFn(fn)) + .catch((err) => handleError(err)); - function callFn(fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result.then( - function () { - done(); - // Return null so libraries like bluebird do not warn about - // subsequently constructed Promises. - return null; - }, - function (reason) { - done(reason || new Error('Promise rejected with no or falsy reason')); + function callFn(fn) { + try { + const result = fn.call(ctx, function (err) { + if (err instanceof Error || toString.call(err) === '[object Error]') { + return done(err); // Error 객체 처리 } - ); - } else { - if (self.asyncOnly) { - return done( - new Error( + if (err) { + if (Object.prototype.toString.call(err) === '[object Object]') { + return done( + new Error('done() invoked with non-Error: ' + JSON.stringify(err)) + ); + } + return done(new Error('done() invoked with non-Error: ' + err)); + } + if (result && utils.isPromise(result)) { + return done( + new Error( + 'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.' + ) + ); + } + done(); + }); + + if (result && typeof result.then === 'function') { + self.resetTimeout(); + + return result + .then(() => { + done(); + // escape Bluebird + return null; + }) + .catch((reason) => { + throw reason || new Error('Promise rejected with no or falsy reason'); + }); + } else { + if (self.asyncOnly) { + throw new Error( '--async-only option in use without declaring `done()` or returning a promise' - ) - ); + ); + } + done(); } - - done(); + } catch (err) { + handleError(err); + } + } + + + function handleError(err) { + errorWasHandled = true; + + if (err instanceof Pending) { + return done(); // Pending 예외 처리 + } + + if (self.allowUncaught) { + throw err; // uncaught 에러 허용 시 throw } + + done(Runnable.toValueOrError(err)); // 나머지 에러 처리 } + function callFnAsync(fn) { var result = fn.call(ctx, function (err) {