【问题标题】:Error handling when getting document from Firestore从 Firestore 获取文档时的错误处理
【发布时间】:2018-08-13 16:34:30
【问题描述】:

在带有 FireStore 和 angularfire2 的 Angular 5 中,通过控制器从服务获取文档时处理错误的正确方法是什么?

服务:

getInviteById( inviteId: string ): Promise<any> {    

    // get requested invite from firestore  
    var inviteDocument = this.afs.collection( 'invites' ).doc( inviteId );
    let invite = inviteDocument.ref.get().then( doc => {

        // if document exists
        if (doc.exists) {

            // return id and data
            const id = doc.id; 
            var data = doc.data() as any;
            return { id, ...data };

        // if document does not exist
        } else {
            console.log("Error: No such document!");

            // WHAT DO I NEED TO RETURN HERE???
        }

    // if other error
    }).catch(function(error) {
        console.log("Error: Getting document:", error);                            

        // WHAT DO I NEED TO RETURN HERE???
    });

    // return invite
    return invite;
};

控制器:

this.inviteService.getInviteById( inviteId )
    .then( resolve => {
        this.invite = resolve;
    })
    .catch( err => {
            // THIS NEVER GETS CALLED !
            console.log("INVITE-COMPONENT: Cannot get invite for this id." );
    });

如果 FireStore 中存在具有邀请 ID 的文档,则一切正常。但是,如果 FireStore 中没有邀请 id 的文档,则服务将记录“错误:没有此类文档!” (如预期的那样),但该组件不会进入自己的 catch 案例。

如何处理我的组件中的“没有此类文档”错误,以便我可以相应地修改我的 UI?

【问题讨论】:

    标签: angular promise google-cloud-firestore angularfire2


    【解决方案1】:

    你可以返回一个被拒绝的承诺,但throw 更简单。

    所以,直截了当,你可以这样写:

    // (1) ILLUSTRATIVE - NOT YET THE FULL SOLUTION
    getInviteById(inviteId: string): Promise<any> {
        var inviteDocument = this.afs.collection('invites').doc(inviteId);
        return inviteDocument.ref.get()
        .then(doc => {
            if (doc.exists) { // if document exists ...
                const id = doc.id;
                var data = doc.data() as any;
                return {id, ...data}; // ... return id and data.
            } else { // if document does not exist ...
                throw new Error('No such document!'); // ... throw an Error.
            }
        })
        .catch(error => {
            throw new Error('Error: Getting document:'); // throw an Error
        });
    };
    

    但是,内部throw 会立即被外部.catch() 捕获,并且“没有这样的文件!”错误消息将丢失,取而代之的是“错误:获取文档:”。

    可以通过如下调整整体模式来避免这种损失:

    // (2) ILLUSTRATIVE - NOT YET THE FULL SOLUTION
    getInviteById(inviteId: string): Promise<any> {
        var inviteDocument = this.afs.collection('invites').doc(inviteId);
        return inviteDocument.ref.get()
        .catch(error => { // .catch() error arising from inviteDocument.ref.get()
            throw new Error('Error: Getting document:');
        })
        .then(doc => {
            if (doc.exists) {
                const id = doc.id;
                var data = doc.data() as any;
                return {id, ...data};
            } else {
                throw new Error('No such document!'); // can now be caught only by getInviteById's caller
            }
        });
    };
    

    但是,即使这样也不正确,因为存在以下可能性:

    1. this.afs.collection('invites').doc(inviteId) 可能返回 null,在这种情况下应该抛出错误。
    2. this.afs.collection('invites').doc(inviteId)inviteDocument.ref.get() 可能会同步抛出

    在任何一种情况下,调用者都有权期望返回承诺的函数总是以异步方式抛出,而不管错误是如何/在何处出现的。

    可以通过确保从承诺链内部执行 var inviteDocument = this.afs.collection('invites').doc(inviteId);inviteDocument.ref.get() 并正确处理 null 情况来克服该工件,如下所示:

    // (3) SOLUTION
    getInviteById(inviteId: string): Promise<any> {
        return Promise.resolve() // neutral starter promise 
        .then(() => {
            var inviteDocument = this.afs.collection('invites').doc(inviteId); // now executed inside promise chain
            if(inviteDocument) {
                return inviteDocument.ref.get(); // now executed inside promise chain.
            } else {
                throw new Error(); // no point setting an error message here as it will be overridden below.
            }
        })
        .catch(error => {
            throw new Error('Error: Getting document:');
        })
        .then(doc => {
            if (doc.exists) {
                const id = doc.id;
                var data = doc.data() as any;
                return {id, ...data};
            } else {
                throw new Error('No such document!');
            }
        });
    };
    

    调用者(您的控制器)将捕获并记录由getInviteById() 引起的任何错误:

    this.inviteService.getInviteById(inviteId)
    .then(result => { // better not to name the variable `resolve`
        this.invite = result;
    })
    .catch(err => {
        console.log("INVITE-COMPONENT: Cannot get invite for this id: " + error.message);
    });
    

    备注

    1. console.log()getInviteById() 中是不必要的(调试时可能除外)。调用者的.catch() 将执行所有必要的日志记录。

    【讨论】:

    • 我已经尝试过您的解决方案,但存在问题。在return inviteDocument.ref.get().catch(error =&gt; { throw new Error('Error: Getting document:'); }); 中,catch() 中的代码不会被执行。相反,任何错误都会导致else { throw new error('No such document!'); }被执行
    • 我现在在平板电脑上。当我回到桌面时会正确回答。
    • 或者我误解了它应该做什么。什么类型的错误会导致它进入 catch 案例?我尝试提供一个无效的集合,但跳过了捕获案例。
    • 捕获当前是嵌套的。尝试将其移入主链以提供...then().catch().then()。再想一想,那会更好。
    • 我已经尝试过了,但没有任何区别。考虑一下,我认为您的代码没有问题,我认为 FireStore 将其视为错误。我对此提出了一个新问题,请参阅stackoverflow.com/questions/49132183/…
    猜你喜欢
    • 2020-12-29
    • 2018-09-03
    • 2022-01-20
    • 2020-10-28
    • 2019-12-22
    • 1970-01-01
    • 2019-07-04
    • 2022-01-06
    • 2019-06-07
    相关资源
    最近更新 更多