链接AngularJS承诺 - 具体案例

时间:2017-08-27 21:33:03

标签: angularjs typescript gmail-api

在我的AngularJS TypeScript代码中,我从我的MainController调用GmailService服务。我需要检索构建这种简单格式的gmail消息列表所需的数据(所有这些都在TypeScript AngularJS中):

export interface GmailMessage {
    from: string;
    subject: string;
    body: string;
}

并将此集合作为承诺返回给控制器。所以我在GmailService服务中写了这个函数来返回这样的集合:

getGmailMessages(): any {
    const deferred = this.$q.defer();
    let gmailMessages: GmailMessage[] = [];
    console.log('getGmailMessages');
    gapi.client["gmail"].users.threads.list({ userId: 'me', labelIds: ['INBOX', 'UNREAD'] }).then(response => {
        let threads = response.result.threads;
        angular.forEach(threads, thread => {
            gapi.client["gmail"].users.messages.get({ userId: 'me', id: thread.id }).then(response => {
                let message = response.result;
                var gmailMessage = {
                    from: message.payload.headers[17].value,
                    subject: message.payload.headers[21].value,
                    body: thread.snippet
                };
                gmailMessages.push(gmailMessage);
            });
        });

        deferred.resolve(gmailMessages);
    });

    return deferred.promise;
}

我知道我对如何实现这一点缺乏一些了解。要获取所需数据,我使用的是Google Gmail。重点是打电话来检索Gmail线程,线程包含一个名为片段的重要属性,我要分配给我的每个GmailMessage.body属性(用于显示),诀窍是对于每个收到的线程对象prmis调用,我需要在线程集合中创建一个消息的单独请求(最后一个)逻辑是这样的,在检索线程列表之后,threadId等于message.id并且可以使用传递的参数来获取信息关于消息(来自,主题等...)这里我使用forEach循环,这在promises的概念中不能正常工作,我知道promise链接,但在这种情况下,对于一个调用来获取我需要的线程进行多次调用以获取每个线程的消息信息。我不明白如何使用promises正确完成它。我试图使用$ q.all(promises)来收集所有的承诺,但我无法理解如何处理所有这些。我的大脑正在爆发对整个事情应该如何运作的误解。最后,我想要的是返回一组GmailMessage对象,其中每个对象都包含3个填充的属性:

var gmailMessage = {
                from: message.payload.headers[17].value,
                subject: message.payload.headers[21].value,
                body: thread.snippet
            };

17是" From"的索引。 21是"主题"

的索引

请问有人澄清这种情况吗?什么应该是最正确的处理方式?例如

deferred.resolve(gmailMessages);

不在正确的位置,并在结果从服务器返回之前立即调用。

如果有人在AngularJS / TypeScript / Google Gmail API中写了类似的内容,请告诉我您是否知道如何实现组合多个承诺的逻辑并在完成所有承诺后对其进行处理。

感谢。

更新

谢谢@AJ Richardson的帮助。我之所以使用旧符号gapi.client [" gmail"]。是VScode中的TypeScript抱怨使用gapi.client.gmail。直接,不知道为什么。相同 - 对于gapi.client.Request - 不理解Request部分,这里是截图(Typescript版本是3.4.1):

enter image description here

我安装了这些依赖项和类型:

"dependencies": {
    "@types/angular": "^1.6.26",
    "@types/angular-sanitize": "^1.3.6",
    "@types/gapi": "0.0.33",
    "@types/gapi.auth2": "0.0.41",
    "@types/jquery": "^3.2.12",
    "angular": "^1.6.5",
    "angular-sanitize": "^1.6.6",
    "bootstrap": "^3.3.7",
    "jquery": "^3.2.1"
}

1 个答案:

答案 0 :(得分:1)

在循环中链接承诺会变得有点复杂。有两种方法可以做到:并行和串行。在这种情况下,您可能希望并行发送请求,因为一个请求的结果不会影响下一个请求。

首先,您应该很少使用$q.defer(),我认为这种情况也不例外。你应该能够完全使用promise chaining(对于parallel或series)。

听起来你正好在并行发送请求的轨道上 - 你只需要存储一个Promise<GmailMessage>[]而不是GmailMessage[]的数组,然后在该数组上调用$q.all 。 e.g。

getGmailMessages(): gapi.client.Request<GmailMessage[]> {
    return gapi.client.gmail.users.threads.list({ userId: 'me', labelIds: ['INBOX', 'UNREAD'] }).then(response => {
        const requests: gapi.client.Request<GmailMessage>[] = response.result.threads.map(thread => {
            return gapi.client.gmail.users.messages.get({ userId: 'me', id: thread.id }).then(response => {
                let message = response.result;
                return {
                    from: message.payload.headers[17].value,
                    subject: message.payload.headers[21].value,
                    body: thread.snippet
                };
            });
        });

        return this.$q.all(requests);
    });
}

我在这里做的是使用map代替forEach进行迭代 - 将每个帖子映射到gapi.client.Request<GmailMessage>(类似于ng.IPromise<GmailMessage>,但使用Google的承诺对象)。然后我等待所有承诺使用$q.all返回。 我还将gapi.client["gmail"]替换为gapi.client.gmail - 如果您使用的是Typescript&gt; = 2.0,则没有理由使用以前的语法。

当然,这是假设gapi.client.Request承诺与ng.IPromise兼容。如果没有,您将需要编写一个实用程序函数来从一种承诺类型转换为另一种承诺类型(可能使用$q.defer())。

相关问题