Обещание и изменение возвращаемого значения - PullRequest
1 голос
/ 17 марта 2019

Мне нужно изменить существующий код для поддержки синхронных и асинхронных результатов. Хотя я легко могу обрабатывать Task и await в C #, даже после прочтения многого из MDN и других страниц, я просто не могу разобраться с JavaScript Promise.

Существующий код выглядит следующим образом:

function dispatchCall() {
    // ...

    try {
        let result = fn.apply(context, args);

        if (result !== undefined) {
            return { status: 0, result: result };
        }
        return { status: 0 };
    }
    catch (err) {
        if (typeof err === "object") {
            return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
        }
        return { status: 400, errorMessage: err };
    }
}

fn - вызываемая функция. Он определяется пользователем моего API, поэтому я не знаю, что он будет делать. На данный момент он всегда будет возвращать значение или выбрасывать исключение. Это значение будет помещено в объект сообщения, который передается удаленному абоненту dispatchCall.

Теперь fn необходимо вернуть Promise, поскольку он должен использоваться в асинхронном рабочем процессе, где результат не доступен сразу.

Мне нужно проверить, является ли result Promise (или "тогда") и действовать соответственно. В этом случае, когда обещание результата разрешено, мне нужно обернуть значение результата в соответствующий объект сообщения и передать его как очередное обещание вызывающей стороне dispatchCall. Тогда я легко справлюсь с этим.

Это то, что "передать и изменить значение" я не могу решить.

Вот как я бы начал:

function dispatchCall() {
    // ...

    try {
        let result = fn.apply(context, args);

        // --------------------------------------------------
        if (result && typeof result.then === "function") {
            result.then(function (result) {
                // Like so?
                if (result !== undefined) {
                    return { status: 0, result: result };
                }
                return { status: 0 };
            })
            .catch(function (err) {
                // Does this catch errors?
                if (typeof err === "object") {
                    return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
                }
                return { status: 400, errorMessage: err };
            });
            return new Promise(function(resolve, reject) {
                // What about this?
                // When should I call resolve and reject and with what arguments?
            });
            // Must return a Promise and not continue at this point!
        }
        // --------------------------------------------------

        if (result !== undefined) {
            return { status: 0, result: result };
        }
        return { status: 0 };
    }
    catch (err) {
        if (typeof err === "object") {
            return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
        }
        return { status: 400, errorMessage: err };
    }
}

Как это должно быть склеено?

Посмотрев таблицы поддержки, я решил отказаться от поддержки Internet Explorer и использовать обещания ES6. Внешняя библиотека не задействована. В случае, если какой-либо IE выполнит это, он должен продолжать работать с синхронными функциями, и ему разрешается сбоить с асинхронным кодом.

Моими целевыми средами являются браузеры и Node.js.

Ответы [ 3 ]

2 голосов
/ 17 марта 2019

Нет необходимости создавать обещание с new Promise, когда у вас есть таблица.

Вы можете просто вернуть return result.then(...... или, если хотите быть уверенным, вернуть экземпляр Promise (а не только то, что возвращает then().catch()), а затем передать результат: Promise.resolve()

    if (typeof result.then === "function") {
        return Promise.resolve(result).then(function (result) {
            if (result !== undefined) {
                return { status: 0, result: result };
            }
            return { status: 0 };
        })
        .catch(function (err) {
            if (typeof err === "object") {
                return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
            }
            return { status: 400, errorMessage: err };
        });
    }

Если в обратном вызове catch произойдет ошибка, возвращенное обещание будет считаться отклоненным. Вызывающий может справиться с этим с помощью собственного catch, связанного с ним.

1 голос
/ 17 марта 2019

Поскольку результат может быть получен асинхронно, потребитель dispatchCall должен иметь логику для ожидания возвращения асинхронных данных.Одним из вариантов было бы для dispatchCall вернуть Обещание, которое в конечном итоге разрешается для объекта { status, result } (или { status, error }), который вы ищете:

if (typeof result.then === "function") {
  return result
    .then((resolveValue) => {
      return { status: 0, result: resolveValue };
    })
    .catch((error) => {
      return { status: 400, error };
    })
}

И у потребителя dispatchCall, проверьте, является ли возвращаемое значение Обещанием - если это так, вызовите .then на нем:

const dispatchResult = dispatchCall();
if (typeof dispatchResult.then === 'function') {
  dispatchResult.then(({ status, result, error }) => {
    // do stuff with status, result, error here
    // if there was an error, result will be undefined
  });
} else {
  // do stuff with dispatchResult.status, .result, .errorMessage
}

Вы также можете рассмотреть возможность возврата Обещания независимо от того, от того, является ли resultявляется Обещанием или нет, чтобы упростить управление кодом - например, в синхронном разделе:

return Promise.resolve({ status: 0, result: result });
0 голосов
/ 18 марта 2019

Вам действительно нужно возвращать этот объект синхронно, когда fn() не возвращает обещание?Было бы намного проще, если бы ваша функция всегда могла вернуть обещание.Вы просто resolve указали бы значение, и независимо от того, было ли это простым значением, потом или обещанием, вы получите от него обещание.

Затем вы бы связали свою логику обработки результатов / ошибок с этимтолько один раз:

function dispatchCall() {
    // ...

    // return Promise.resolve(fn.apply(context, args))… - doesn't catch synchronous exceptions
    return new Promise(function(resolve) {
        resolve(fn.apply(context, args)); // promise constructor catches exceptions
    }).then(function (result) {
        // the promise was fulfilled
        if (result !== undefined) {
            return { status: 0, result: result };
        } else {
            return { status: 0 };
        }
    }, function (err) {
        // the promise was rejected
        if (typeof err === "object") {
            return { status: 400, errorMessage: err.name + ", " + err.message, stack: err.stack };
        } else {
            return { status: 400, errorMessage: err };
        }
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...