正确承诺处理成功和错误回调

时间:2017-03-17 14:26:11

标签: javascript reactjs typescript redux

我在TypeScript中有以下服务从后端获取数据。

作为函数getAllPropertiesByAppId的参数,我有一个成功和错误回调。

export class PropertyService implements IPropertyService {

/**
 * Get all properties
 */
public getAllPropertiesByAppId(appliactionId: string, success: (properties: Array<IPropertyItem>) => void, error: (error: any) => void): void {              

    //set up createRequestStr and requestInit

    fetch(createRequestStr, requestInit)
        .then<IPropertyItem[]>((response: Response) => {
            if (response.status===401) {
                throw new UnAuthorizedException();
            }
            return response.json<IPropertyItem[]>();
        })
        .then((response: IPropertyItem[]) => {               
            success(response);
        })
        .catch((reason: any) => {
            //error handling
            }
        });
}

然后我在我的动作创建者中使用此服务:

 initProperties: (appId: string): ActionCreator => (dispatch: Redux.Dispatch, getState: () => IApplicationState) => {
    "use strict";

    console.log("ShoppingCart initProperties - Request all Property");

    var service: IPropertyService = kernel.get<IPropertyService>("IPropertyService");

    service.getAllPropertiesByAppId(appId, (properties: Array<IPropertyItem>): void => {

        dispatch(new ShoppingCartPropertiesLoaded(appId, properties));
        dispatch(new ShoppingCartPropertiesDone(appId, System.Init.Done));            

    }, (error: any): void => {
        console.log("ShoppingCart initProperties - error:" + error);
        dispatch(new ShoppingCartPropertiesDone(appId, System.Init.Error));
    });
}

因此,当我调用initProperties动作创建器时,它调用getAllPropertiesByAppId,当一切正常时,我将调度ShoppingCartPropertiesLoaded和ShoppingCartPropertiesDone。

我有一个连接到store的简单组件,当执行render方法时组件会抛出错误

export default class TotalPriceList extends React.Component<ITotalPriceListProps, void> {

public render(): JSX.Element {

    throw 'SomeError';
}
}

未处理的异常最终出现在fetch的catch语句中。

我是否遗漏了如何正确退出promise甚至更好地如何从语句和退出promise中调用函数/回调,以避免在fetch的catch语句中从回调中捕获异常?

非常感谢你的帮助

2 个答案:

答案 0 :(得分:2)

  

作为函数getAllPropertiesByAppId的参数,我有成功和错误回调。

那是你的实际问题。您应该始终从异步函数返回一个promise。 停止使用回调参数!

您的代码应该是

/**
 * Get all properties
 */
public getAllPropertiesByAppId(appliactionId: string): Promise<IPropertyItem[]> {
    //set up createRequestStr and requestInit
    return fetch(createRequestStr, requestInit)
//  ^^^^^^
    .then<IPropertyItem[]>((response: Response) => {
        if (response.status===401) {
            throw new UnAuthorizedException();
        }
        return response.json<IPropertyItem[]>();
    });
}

这会偶然解决您未经处理的拒绝问题。通过不结束链但返回承诺,你像往常一样将处理错误的责任放在调用者身上。此外,调用者隐含地负责他在他的承诺回调中所做的任何事情 - 他们根本不涉及承诺返回方法。

你因此使用

service.getAllPropertiesByAppId(appId).then((properties: Array<IPropertyItem>): void => {
//                                    ^^^^^
    dispatch(new ShoppingCartPropertiesLoaded(appId, properties));
    dispatch(new ShoppingCartPropertiesDone(appId, System.Init.Done));            
}, (error: any): void => {
    console.log("ShoppingCart initProperties - error:" + error);
    dispatch(new ShoppingCartPropertiesDone(appId, System.Init.Error));
}).catch((reason: any) => {
    // error handling for a failed dispatch
});

答案 1 :(得分:0)

如果您不想在承诺链中捕获异常,则只需在最后删除.catch来电。

但请记住,您将无法使用try {} catch (error) {}块捕获此错误。相反,它会冒泡到最高级别会收到unhandledRejection

如果我理解正确,您将回调(success)传递给getAllPropertiesByAppId,它返回一个调用回调的承诺; fetch(…).then(success)基本上。所以你所经历的完全是对promises中包含的函数内异常的定义行为。

您可能希望切换到使用promise,而不是混合连续传递样式(回调)和承诺。

像(伪代码js,而不是抱歉)

class Service {
  getAllPropertiesByAppId (appId) {
    return fetch(createRequestStr, requestInit)
           .then(response => response.json());
  }
};

// …

service.getAllPropertiesByAppId(…)
.then(dispatchAllTheThings)
.catch(error => { console.log(…); dispatch(…) })

在调用.catch之后,在调度组件中抛出异常将被捕获到promise链中的dispatchAllTheThings内。