javascript - AngularJS ve Typescript ile Promiseler
Aşağıdaki fonksiyona sahibim, amacım bileşenlerin kendi üst öğelerini tanıyabildiğinde items listesine eleman eklemek. Yaşadığım sorun şu ki, listeye ekleme yaptığımda console.log() bana nesnenin orada olduğunu gösteriyor, fakat listeyi döndürüp başka bir fonksiyonda yakaladığımda listede hiçbir şey yok. Sanırım items listesi yukarıdaki kod tamamlanmadan önce döndürülüyor.
private get_items_for_request() {
return this.Item.forRequest(this.request.id, ['group'])
.then((_items) => {
var items = [];
for (var item of _items) {
return this.ItemComponent.forItem(item.id, ['type'])
.then((_components) => {
for (var component of _components) {
if (component.type.can_identify_item) {
items.push({
group_id: item.group.reference,
identifier_code: this.remove_check_digit_if_necessary(
component.identifier_code),
quantity: 1
});
break;
}
}
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('components.load_failed'));
return [];
});
}
return items;
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('items.failed_load'));
return [];
});
}
Cevap #1
Korkarım sorun kodun kendisinde değil, yaklaşımınızda. Bir promise sadece bir şeydir - gelecekte bir zamanda veri sözü. Yani, fonksiyonunuz döndüğünde (hemen), promise henüz çözülmemiştir ve çağıran fonksiyonunuzun aldığı veri hâlâ boştur. Kodunuzda console.log() görmüyorum, ama muhtemelen onu then() içinde bir yere koyduğunuzu düşünebilirim; bu, veri alındığında çağrılır. Böylece verinin loglandığını görürsünüz. Sorun şu ki o zamana kadar get_items_for_request() zaten döndü ve çağıran fonksiyonunuz çoktan devam etti.
Bir promise kullanmak istiyorsanız, promise çözüldüğünde çağrılacak bir callback kullanmanız gerekir. Ancak çağırana gerçek veri döndürmek istiyorsanız veriyi senkron olarak almanız gerekir.
Senkron veri çekme için, bu cevabı kontrol edin. Ancak, senkron veri çekmenin scriptinizin yanıt verme hızını olumsuz etkileyeceğine dikkat edin.
Asenkron bir veri çekme işlemi için (promiseleri kullanarak), tüm veriler alındığında bir kez çağrılacak bir geri çağırma (callback) tanımlamanız gerekir. Kodunuzu düzeltmeye çalışmayacağım, ancak Javascript’te aşağıdaki taslak gibi olmalıdır. Yine de bunun sadece bir taslak olduğunu unutmayın.
function get_items_for_request(onSuccess) {
var items = []
var total = -1
var sofar = 0;
this.Item.forRequest(this.request.id, ['group'])
.then(function (_items) {
var items = [];
total = _items.length // remember how many nested calls will be made
for (var item of _items) {
this.ItemComponent.forItem(item.id, ['type'])
.then(function (_components) {
// push received data to the items array here
sofar++
if (sofar == total) { // all done
onSuccess(items)
}
}
}
}
}
Cevap #2
İlk promise geri çağırmasında iki return var, sadece ilki çalışır. İlk for'dan sonra bir promise döndürüyorsun, bu promise undefined olarak çözülüyor. Her biri bir this.ItemComponent.forItem çağrısına karşılık gelen bir dizi promise için beklemelisin.
Promise.all bu konuda yardımcı olur: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Böyle bir şey yapmalısın:
return this.Item.forRequest(this.request.id, ['group']).then((_items) => {
return Promise.all(_items.map(function (item) {
return this.ItemComponent.forItem(item.id, ['type']).then((_components) => {
for (var component of _components) {
if (component.type.can_identify_item) {
return {
group_id: item.group.reference,
identifier_code: this.remove_check_digit_if_necessary(
component.identifier_code),
quantity: 1
};
}
}
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('components.load_failed'));
return [];
});
}));
}, (reason) => {
this.Toast.error(
this.gettextCatalog.getString('items.failed_load'));
return [];
} )
Eğer sadece bir öğe istiyorsanız, oluşan dizideki ilk yanlış olmayan öğeyi bulun
