从Firestore获取文档时的错误处理

时间:2018-03-05 22:09:38

标签: angular promise google-cloud-firestore angularfire2

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

服务:

Sub Compress(filename As String, zippedFile As String)
    If IO.File.Exists(zippedFile) Then IO.File.Delete(zippedFile)

    If IO.File.Exists(filename) Then
        Using archive As ZipArchive = Open(zippedFile, ZipArchiveMode.Create)
            archive.CreateEntryFromFile(filename, Path.GetFileName(filename), CompressionLevel.Fastest)
        End Using
    End If
End Sub

控制器:

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

如果FireStore中存在具有invite-id的文档,则一切正常。但是,如果FireStore中没有邀请ID的文档,则该服务将记录“错误:没有此类文档!” (正如预期的那样),但该组件不会进入自己的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." ); }); 案例。

如何处理组件中的“无此类文档”错误,以便我可以相应地修改我的用户界面?

1 个答案:

答案 0 :(得分: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()可能会同步
  3. 在任何一种情况下,调用者都有权期望一个promise-returns函数总是抛出异步,无论错误发生的方式/位置如何。

    可以通过确保从promise链内执行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);
    });
    

    备注

      {li> console.log()getInviteById()内是不必要的(调试时除外)。来电者.catch()将执行所有必要的记录。