简体   繁体   English

如何构造一个 Promise,在其中调用异步函数,解析结果,然后解析/拒绝?

[英]How to construct a Promise that calls an async function inside of it, parses the result, and then resolves/rejects?

I would like to write a function getUser() that returns a Promise where upon resolve it delivers the user object and upon reject it delivers the error.我想编写一个函数getUser() ,它返回一个 Promise ,它在resolve时传递用户对象,在reject时传递错误。 I'm using axios to make the request.我正在使用 axios 提出请求。

Here's what I currently have.这是我目前拥有的。

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);
    }

}

I would like to wrap the entire try...catch block inside a Promise constructor, but the Promise constructor is new Promise((resolve, reject) => {...}) and not new Promise(async (resolve, reject) => {...}) .我想将整个try...catch块包装在Promise构造函数中,但 Promise 构造函数是new Promise((resolve, reject) => {...})而不是new Promise(async (resolve, reject) => {...}) I know I can do the latter but it's an anti-pattern .我知道我可以做后者,但这是一种反模式

The Promise approach doesn't necessarily work either because when I use the Promise returned by getUser() and .catch() any errors, I won't know if the error came from the response from the server (the status was not 'success' ) or if the request itself failed. Promise方法也不一定有效,因为当我使用getUser().catch()返回的Promise时出现任何错误,我不知道错误是否来自服务器的响应(状态不是'success' ) 或者如果请求本身失败。

What is the safest way to get around this problem?解决这个问题的最安全方法是什么? I know there is a brute force solution of just mimicking the Promise API without actually using it, or declaring an async Promise, but I feel like I'm encountering an anti-pattern every time.我知道有一个蛮力的解决方案,就是在不实际使用的情况下模仿Promise API,或者声明一个async Promise,但我觉得我每次都遇到了反模式。

Thanks for any suggestions.感谢您的任何建议。

I'll answer this conceptually.我将从概念上回答这个问题。

When you call an async function, it immediately returns a promise to the code-scope that called that function.当您调用异步函数时,它会立即向调用该函数的代码范围返回一个承诺。

Inside of an async function, you don't need to use resolve and reject .在异步函数内部,您不需要使用resolvereject Instead you can just use return and throw .相反,您可以只使用returnthrow What ever you return is what the promise will resolve to.return就是承诺将解决的问题。 If you throw , that's what the promise will "reject" to.如果您throw ,这就是承诺将“拒绝”的内容。 Try something like this:尝试这样的事情:

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;
    }
}

After async/await came out, I stopped liking the then syntax when dealing with promises.在 async/await 出现后,我在处理 promise 时不再喜欢then语法。 To avoid then , call getUser from the body of an async function.为避免then ,请从异步函数的主体中调用getUser If you're not calling getUser from the body of an async function, you won't be able to await what it resolves to;如果您不是从异步函数的主体中调用getUser ,您将无法await它解析为的内容; you'll have to use then instead.你将不得不使用then代替。 Or, you can wrap that calling code in an immediately invoked async function just so you can indeed uses await .或者,您可以将该调用代码包装在立即调用的异步函数中,以便您确实可以使用await Here's a rough example of how my code (that calls getUser ) might look:这是我的代码(调用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.
})();

The only reason I'm wrapping the code above in an immediately invoked async function, is so I can use await instead of then to resolve that promise.我将上面的代码包装在一个立即调用的异步函数中的唯一原因是,我可以使用await而不是then来解决该承诺。

Functions marked with async are meant to be written using promise .then() callback style.标有async函数旨在使用 promise .then()回调样式编写。 That is, in order to resolve a value you use the return keyword and in order to reject a value you use the throw keyword.也就是说,为了解析一个值,你使用return关键字,为了拒绝一个值,你使用throw关键字。 Thus your function should be written as follows:因此,您的函数应编写如下:

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);
    }

}

The Promise approach doesn't necessarily work either because when I use the Promise returned by getUser() and .catch() any errors, I won't know if the error came from the response from the server (the status was not 'success') or if the request itself failed. Promise 方法也不一定有效,因为当我使用 getUser() 和 .catch() 返回的 Promise 时出现任何错误,我不知道错误是否来自服务器的响应(状态不是 'success ') 或者如果请求本身失败。

I would look at rejecting the outer promise inside getUser in one of two examinable ways - and then call getUser using a promise topology that splits good data into a processing stream (chain of promises), and errors into another for differentiation.我会考虑以两种可检查的方式之一拒绝getUser内部的外部承诺 - 然后使用承诺拓扑调用getUser ,该拓扑将好的数据拆分为处理流(承诺链),并将错误拆分为另一个以进行区分。 For example:例如:

  1. Create a data wrapper constructor called, say, GetUserData:创建一个名为 GetUserData 的数据包装器构造函数:

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

    This may benefit from having another parameter for getUser argument values.这可能会受益于为getUser参数值设置另一个参数。

  2. Remove the try { and catch() {} clauses.删除try {catch() {}子句。 Let axios errors throw and reject the getUser promise.让 axios 错误抛出并拒绝getUser承诺。

  3. Have getUser return the result of "success" or throw a GetUserData object:getUser返回“成功”的结果或抛出一个GetUserData对象:

     if (userResponse.data.status === 'success') { return userResponse.data; } else { throw new GetUser( userResponse.data); }
  4. Call getUser with a topology that differentiates the error types:使用区分错误类型的拓扑调用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 })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM