如何在 Ionic 3 中执行多个异步操作并在一切完成后关闭加载器?
Posted
技术标签:
【中文标题】如何在 Ionic 3 中执行多个异步操作并在一切完成后关闭加载器?【英文标题】:How to perform multiple asynchronous actions in Ionic 3 and dismiss a loader after everything is done? 【发布时间】:2018-05-09 10:26:22 【问题描述】:我开发了一个 Ionic 3 应用程序,它可以选择按需缓存文章内容列表。我正在使用Storage
,它使用承诺进行操作。
我的代码如下:
article-service.ts
getArticleFullData(articleId: number)
let appSettings = this.appSettingsService.getSettings();
let params = this.utilsService.serializeQueryParams(appSettings);
let url = `$this.apiBasePathArticle/GetArticleFullData?articleId=$articleId&$params`;
this.loggingService.logInfo("Getting article full data from url " + url);
return this.http.get(url)
.map(res => res.json());
article-cache-service.ts
// saves a single article to the cache
private saveToCache(articleId: number): Observable<any>
let key = articleId;
let obs = this.articleService.getArticleFullData(key);
obs.subscribe(data =>
this.storage.set(this.GetArticleFullKey(key), data as ArticleFullData);
,
err =>
this.loggingService.logError("Failed to cache data for article: " + key);
);
return obs;
// tries to cache a list of article in the cache
// avoids overwriting the data, if exists
public saveArticleDataToCache(articles: ArticleBriefData[]): Observable<[]>
var obsArray = [];
for (let article of articles)
let key = this.GetArticleFullKey(article.ArticleId);
this.storage.get(key)
.then(data =>
console.log("Storage data for article " + key, data);
if (!data)
obsArray.push(this.saveToCache(article.ArticleId));
)
.catch(err =>
this.loggingService.logError("Failed to check storage for key " + key, err);
);
var ret = Observable.forkJoin(obsArray);
return ret;
包含加载器的代码
this.loadingCtrl.create( content: "Caching data. Please wait..." );
this.loadingCtrl.present();
var all = this.articleCacheService.saveArticleDataToCache(this.articles);
var subscr = all
.toPromise()
.then(data =>
console.log("All data: ", data);
this.loadingCtrl.dismiss();
this.loggingService.logInfo("Successfully cached articles ");
)
.catch(err =>
this.loadingCtrl.dismiss();
this.loggingService.logError("Failed to cache data: ", JSON.stringify(err));
);
缓存过程正确执行,但then
代码立即执行(data
是undefined
)
我也尝试过subscribe
的方法,但是subscribe
中的代码似乎没有被执行(虽然缓存被正确执行了):
var all = this.articleCacheService.saveArticleDataToCache(this.articles);
var subscr = all
.subscribe(data =>
console.log("All data: ", data);
this.loadingCtrl.dismiss();
this.loggingService.logInfo("Successfully cached articles ");
,
err =>
this.loadingCtrl.dismiss();
this.loggingService.logError("Failed to cache data: ", JSON.stringify(err));
);
我显然无法在这里与Observable
s 正常合作。
问题:如何在 Ionic 3 中执行多个异步操作并在所有操作完成后关闭加载器?
【问题讨论】:
【参考方案1】:您可以使用forkjoin
轻松做到这一点。
注意:我已从我的应用程序中提取代码。因此请根据您的用例进行更改。如果您使用的是RXJS 5.5.2
,请更改imports
根据最新changes here
import Observable from "rxjs/Observable";
import 'rxjs/add/observable/forkJoin'
let myTopicApi = this.getMytopic();
let myarticlApi = this.getMyArticles();
let myPicksAPi = this.getMyPicks();
Observable.forkJoin([myTopicApi, myarticlApi, myPicksAPi])
.subscribe(res =>
this.arrangeMytopics(res[0]);
this.arrangeMyArticles(res[1]);
this.arrangeMyPicks(res[2]);
if (loading) loading.dismiss(); loading = null; //here you can dismiss your loader
,
error => if (loading) loading.dismiss(); loading = null; //here you can dismiss your loader ,
() => );
getMytopic()
return this.topicSer.getMyTopics().map((res: any) => res.json()).map((res: any) => res = res.categories)
.catch((err: any) => )
【讨论】:
感谢您的快速回答。我正在使用rxjs 5.4.0
。我的代码已经在使用forkJoin
,但它没有按预期工作。这可能与 getArticleFullData
正在做的事情有关,但我无法弄清楚出了什么问题(我也添加了该函数的代码)。
试试let
而不是var
看看。
而且您似乎没有正确使用forkjoin
。我已经更新了我的帖子。希望您能更好地了解如何使用forkjoin
。
我意识到我做错了什么。我用于forkJoin
的obsArray
是在this.storage.get(key)
的then
中构造的。我已将代码简化为将“saveToCache”(返回Observable
)推送到数组中,并且工作正常。但是,我丢失了缓存中存在的检查(我不明白为什么存储也不允许同步方法),但如果我不知道如何解决它,这是另一个问题的问题。
是的,问题是您尝试同时使用observable
和promise
。但是您不能那样使用。您必须将observable
转换为promise
或将promise
转换为observable
。然后该问题也将消失。【参考方案2】:
Sampath
的回答帮助我找到了问题所在。我做错的是我构造Observable
数组的方式(它在forkJoin
中使用):在存储get返回的Promise
的then
函数内推入列表。
修复此问题后我的代码还包括检查项目是否存在(以避免 HTTP 调用和重置存储数据):
article-service.ts
getArticleFullData(articleId: number)
let appSettings = this.appSettingsService.getSettings();
let params = this.utilsService.serializeQueryParams(appSettings);
let url = `$this.apiBasePathArticle/GetArticleFullData?articleId=$articleId&$params`;
return this.http.get(url)
.map(res => res.json());
article-cache-service.ts
我正在使用flatMap
链接Observable
通过检查存储是否已经具有密钥和实际获取。如果数据存在,我会返回一个空的Observable
以实际取消该过程。
private saveToCache(articleId: number): Observable<any>
let key = this.GetArticleFullKey(articleId);
let storageObs = Observable.fromPromise(this.storage.get(key));
let getArticleObs = this.articleService.getArticleFullData(articleId);
let obs = storageObs.flatMap(data =>
if (!data)
return getArticleObs;
else
return Observable.of(null);
);
obs.subscribe(data =>
if (data)
this.storage.set(key, data as ArticleFullData);
,
err =>
this.loggingService.logError("Failed to cache data for article: " + articleId);
);
return obs;
public saveArticleDataToCache(articles: ArticleBriefData[]): Observable<[]>
let obsArray = [];
for (let article of articles)
let obs = this.saveToCache(article.ArticleId);
obsArray.push(obs);
let ret = Observable.forkJoin(obsArray);
return ret;
实际订阅
onCacheRefresh()
// articles are not loaded for some reason
if (!this.articles)
return;
this.loadingCtrl.create( content: "Caching data. Please wait..." );
this.loadingCtrl.present();
let all = this.articleCacheService.saveArticleDataToCache(this.articles);
let subscr = all
.subscribe(data =>
console.log("All data: ", data);
this.loadingCtrl.dismiss();
this.loggingService.logInfo("Successfully cached articles ");
,
err =>
this.loadingCtrl.dismiss();
this.loggingService.logError("Failed to cache data: ", JSON.stringify(err));
);
【讨论】:
以上是关于如何在 Ionic 3 中执行多个异步操作并在一切完成后关闭加载器?的主要内容,如果未能解决你的问题,请参考以下文章
ionic3 异步请求中.then的作用,以及如何理解JavaScript Promise