Как создать Promise, который вызывает внутри него асинхронную c функцию, анализирует результат, а затем разрешает / отклоняет? - PullRequest
0 голосов
/ 27 января 2020

Я хотел бы написать функцию getUser(), которая возвращает Обещание, где при resolve доставляет объект пользователя, а при reject выдает ошибку. Я использую топор ios, чтобы сделать запрос.

Вот что у меня сейчас есть.

async function getUser() {

    try {
        const userResponse = await axios({
            method: 'post',
            url: "some_url",
            data: "some string data",
            headers: {
                'content-type': 'application/x-www-form-urlencoded'
            }
        });
        if (userResponse.data.status === 'success') {
            // resolve(validateResponse.data);
        } else {
            // reject(validateResponse.data);
        }
    } catch (error) {
        // reject(validateResponse.data);
    }

}

Я бы хотел обернуть весь блок try...catch внутри Promise конструктор, но конструктор Promise new Promise((resolve, reject) => {...}), а не new Promise(async (resolve, reject) => {...}). Я знаю, что могу сделать последнее, но это анти-паттерн .

Подход Promise тоже не обязательно работает, потому что когда я использую Promise, возвращаемый getUser() и .catch() никаких ошибок, я не буду знать, произошла ли ошибка в ответе от сервера (статус не был 'success') или если сам запрос не прошел.

Какой самый безопасный способ обойти эту проблему? Я знаю, что есть грубое решение, просто имитирующее API Promise без его фактического использования или объявление async Promise, но я чувствую, что каждый раз сталкиваюсь с анти-паттерном.

Спасибо за любые предложения.

Ответы [ 3 ]

2 голосов
/ 27 января 2020

Я отвечу на это концептуально.

Когда вы вызываете асинхронную функцию c, она немедленно возвращает обещание области кода, которая вызвала эту функцию.

Внутри Функция asyn c, вам не нужно использовать resolve и reject. Вместо этого вы можете просто использовать return и throw. То, что вы когда-либо return, - это то, к чему обещание примет Если вы throw, то это обещание будет «отклонено». Попробуйте что-то вроде этого:

async function getUser() {

    try {
        const userResponse = await axios({
            method: 'post',
            url: "some_url",
            data: "some string data",
            headers: {
                'content-type': 'application/x-www-form-urlencoded'
            }
        });
        if (userResponse.data.status === 'success') {
            return validateResponse.data;
        } else {
            throw new Error(validateResponse.data);
        }
    } catch (error) {
        throw error;
    }
}

После выхода async / await я перестал любить синтаксис then при работе с обещаниями. Чтобы избежать then, вызовите getUser из тела asyn c функции. Если вы не вызываете getUser из тела асинхронной c функции, вы не сможете await разрешить то, к чему она относится; вам придется использовать then вместо этого. Или вы можете обернуть этот вызывающий код в , немедленно вызванную asyn c функцию , просто чтобы вы действительно могли использовать await. Вот грубый пример того, как мой код (который вызывает getUser) может выглядеть:

(async function()
{
    let user = await getUser();
    if(!user)
    {
        console.error(`Access Denied`);
        return;
    }
    // Rest of your code that should only run when you have a user goes here.
})();

Единственная причина, по которой я обертываю код выше в немедленно вызываемой асинхронной c функции, заключается в том, что я можно использовать await вместо then для разрешения этого обещания.

1 голос
/ 27 января 2020

Подход Promise также не обязательно работает, потому что когда я использую Promise, возвращаемый getUser () и .catch (), любые ошибки, я не буду знать, произошла ли ошибка в ответе от сервера ( статус не был «успешным») или если сам запрос не удался.

Я бы посмотрел на отклонение внешнего обещания внутри getUser одним из двух возможных способов - и затем вызвал getUser, используя топология обещаний, которая разделяет хорошие данные в поток обработки (цепочка обещаний) и ошибки в другой для дифференциации. Например:

  1. Создайте конструктор оболочки данных, скажем, скажем, GetUserData:

    const GetUserData = function( data) {
        this.data = data;
    }
    

    Может быть полезно иметь другой параметр для getUser значений аргумента.

  2. Удалить пункты try { и catch() {}. Пусть ax ios выдает ошибки и отклоняет обещание getUser.

  3. Пусть getUser вернет результат "success" или throw a GetUserData объект:

    if (userResponse.data.status === 'success') {
        return  userResponse.data;
    }
    else {
        throw new GetUser( userResponse.data);
    }
    
  4. Вызов getUser с топологией, которая различает типы ошибок:

    let userPromise = getUser(); // parameterized?
    userPromise.then(data => { do something with user data}); // chain promises on "success" as needed
    
    // split errors into a .then handler for server errors and a .catch handler for axios errors:
    
    userPromise.catch( something => {
       if( something instanceOf GetUserData) {
           return something.data;
       }
       throw something; // rethrow axios error
    })
    .then ( data =>  { deal with unsuccessful server data})
    .catch( error => { deal with axios error })
    
1 голос
/ 27 января 2020

Функции, отмеченные async, предназначены для написания в стиле обратного вызова обещания .then(). То есть для разрешения значения используется ключевое слово return, а для отклонения значения используется ключевое слово throw. Таким образом, ваша функция должна быть записана следующим образом:

async function getUser() {

    try {
        const userResponse = await axios({
            method: 'post',
            url: "some_url",
            data: "some string data",
            headers: {
                'content-type': 'application/x-www-form-urlencoded'
            }
        });
        if (userResponse.data.status === 'success') {
            return validateResponse.data;
        } else {
            throw new Error(validateResponse.data);
            // Alternately you can also just:
            // throw validateResponse.data
        }
    } catch (error) {
        throw new Error(validateResponse.data);
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...