Angular 2/4 Typescript'te fonksiyonlar nasıl sıralı olarak çalıştırılır
Angular 2/4 projemde fonksiyonları sıralı bir şekilde çalıştırmaya çalışırken sorun yaşıyorum.
retrieveData() fonksiyonum, veri servisinden veri alır ve bunları, benim tanımladığım bir diziye atar.
Sonra, dizide saklanan verileri kullanan ve bunları bir grafikte gösteren displayData() fonksiyonuna sahibim.
Onları çalıştırmaya çalıştığımda, örneğin:
function(){
this.retrieveData();
this.displayData();
}
displayData() fonksiyonu, esas olarak retrieveData() fonksiyonundaki veri hizmeti nedeniyle retrieveData() fonksiyonundan önce çalışır. Bu nedenle grafik düzgün bir şekilde görüntülenemez.
Fonksiyonları sırayla çalıştırabileceğim yöntemlerden biri, async kütüphanesinden async.waterfall, ancak kütüphaneyi projemde içe aktarmakta sorun yaşıyorum ve konsol şunu söylüyor: Uncaught Error: Unexpected value 'waterfall' imported by the module 'AppModule'. Please add a @NgModule annotation.
Promises ve Observables kullanmak istemiyorum çünkü bunlar, sonraki fonksiyonlara iletmek için başlangıç fonksiyonunun bir tür dönüş değerine sahip olmasını gerektiriyor. Bunu bir şekilde setTimeOut() fonksiyonunu kullanarak başarmayı başardım ama yaklaşımın güvenilirliği ve sağlamlığı konusunda gerçekten şüpheliyim.
Yani, Angular 2/4'te async kullanımına dair herhangi bir yardım veya fonksiyonları herhangi bir dönüş vaadi olmadan bekletmenin herhangi bir yolu var mı?
GÜNCELLEME
Karışıklık ve verdiğim rahatsızlık için özür dilerim arkadaşlar. Basitleştirilmiş bir versiyonunu yayınlayıp sormuştum. İşte kodumun daha tamamlanmış kısmı. Ben Angular ve Typescript konusunda acemiyim, Async programlama tekniklerinde ise daha da acemiyim.
Aşağıda retrieveAllData() metodundaki promises uygulamam bulunmaktadır. Ne derleme zamanında ne de çalışma zamanında herhangi bir hata vermiyor. Ancak fonksiyonlar hâlâ asenkron olarak çalışırken, yani refreshAllCharts() hâlâ retrieveAllData()'den önce çalışıyor. Promises uygulamamda herhangi bir kusur var mı?
import { Component, OnInit, AfterContentInit } from '@angular/core';
import { DataService } from '../data.service';
import {BaseChartDirective} from 'ng2-charts/ng2-charts';
import {IMyDpOptions,IMyDateModel} from 'mydatepicker';
//import {MomentTimezoneModule} from 'angular-moment-timezone';
import * as moment from 'moment-timezone';
// import async from 'async-waterfall';
@Component({
templateUrl: 'chartjs.component.html'
})
export class ChartJSComponent {
tempArr = []; //array to store temperature values for the chart
timeTempArr = []; //array to store timestamps for the chart label
device = "1CB001"; //a parameter used for the data service method to query the database
dateSelected; //variable to store the date chosen from the datepicker on the html side of the component
constructor(private dataService: DataService){
}
ngOnInit(){
}
//function to retrieve temperature values and assign them into "tempArr" array
retrieveTempDataAssign(){
var _arr = new Array();
this.dataService.getData(this.device, this.dateSelected).subscribe(response => {
console.log("Response: " + JSON.stringify(response));
for(var item of response){
_arr.push(item.Temperature);
}
this.tempArr = _arr;
console.log("Array assigned Temp: " + this.tempArr);
});
this.retrieveTempTimeDataAssign();
}
//function to retrieve time values and assign the date and time objects into "timeTempArr" array
retrieveTempTimeDataAssign(){
var _arr = new Array();
this.dataService.getData(this.device, this.dateSelected).subscribe(response => {
for(var item of response){
// var value = "'" + item.Date + "'";
// _arr.push(value);
var value = item.Date;
var time = moment.tz(value, "Asia/singapore");
_arr.push(time);
}
this.timeTempArr = _arr;
console.log("Array assigned Time: " + this.timeTempArr);
});
}
//function to refresh the whole of Temperature chart
refreshTempChart(){
this.showTempData();
setTimeout(() => this.showTempLabels(), 500);
}
//function to assign the "tempArr" array into the dataset for the temperature chart
showTempData(){
console.log("To display: " + this.tempArr);
this.datasetsTemp = [{
label: "Values",
data: this.tempArr
}];
}
//function to assign the "timeTempArr" array into the labels for the temperature chart
showTempLabels(){
console.log("To label: " + this.timeTempArr);
this.labels = this.timeTempArr;
}
//date picker format
private myDatePickerOptions: IMyDpOptions = {
dateFormat: 'yyyy-mm-dd',
};
//change event listener on the datepicker
onDateChanged(event: IMyDateModel){
this.dateSelected= event.formatted;
console.log("Selected Date: " + this.dateSelected);
//**The implementation part**
this.retrieveAllData().then(()=>{
this.refreshAllCharts();
})
}
//to run all functions to retrieve respective data
retrieveAllData(){
return new Promise((resolve, reject) => {
this.retrieveTempDataAssign(); //assign the retrieved values into the array first
return true;
});
}
//to run all functions to update all the charts
refreshAllCharts(){
this.refreshTempChart();
}
//objects used by the chart to display data
private datasetsTemp = [
{
label: "Values",
data: []
}
];
private labels = [];
private options = {
scales: {
xAxes: [{
display: true,
type: "time",
time: {
unit: "hour",
tooltipFormat: 'YYYY-MM-DD hh:mm A'
},
scaleLabel: {
display: true,
labelString: 'Time'
}
},],
yAxes: [{
ticks: {
beginAtZero: false
}
}]
}
};
}
Cevap #1
Promise kullanırken bir sonraki fonksiyonlara aktarmak için herhangi bir değer döndürmek zorunda değilsiniz. Fonksiyon imzanızı değiştirmeden (ör. retrieveData() ve displayData() hiçbir parametre almaz ve void döndürür) kullanmak istiyorsanız, promise'leri şöyle kullanmayı düşünebilirsiniz:
private dataStorage: string = null;
private retrieveDataResolver;
displayData(): void {
// your display code goes here
console.log("2. DISPLAYING DATA", this.dataStorage);
}
retrieveData(): void {
// your async retrieval data logic goes here
console.log("1. GETTING DATA FROM SERVER");
setTimeout(() => { // <--- Change it - your service data retrieval
this.dataStorage = '++DATA++';
this.retrieveDataResolver(); // <--- This must be called as soon as the data are ready to be displayed
}, 1000);
}
retrieveDataPromise(): Promise<any> {
return new Promise((resolve) => {
this.retrieveDataResolver = resolve;
this.retrieveData();
})
}
retrieveAndThenDisplay() {
this.retrieveDataPromise().then(() => {this.displayData()});
}
Asenkron işlemleri sıraya koymak için güçlü bir zincirleme yapısı olarak promise sarmalayıcısı kullanmanızı tavsiye ederim
Cevap #2
Güncellemenizin yanında, promise zincirleyebilirsiniz. Önce veriyi alın ve veri hazır olduğunda çağrılan graphe'i yenileyin. Bu bağlantı, promise'leri daha iyi anlamanıza yardımcı olabilir: https://codecraft.tv/courses/angular/es6-typescript/promises/
// get data
var job1 = new Promise(function(resolve, reject){
resolve('done1');
});
job1.then(function(data) {
refreshGraphe();
})
