Array.map ile eşzamansız kullanımı kullan


171

Aşağıdaki kod verildiğinde:

var arr = [1,2,3,4,5];

var results: number[] = await arr.map(async (item): Promise<number> => {
        await callAsynchronousOperation(item);
        return item + 1;
    });

Bu da aşağıdaki hatayı üretir:

TS2322: 'Promise <sayı> []' tipi, 'sayı []' türüne atanamaz. 'Promise <sayı> türü,' sayı 'türüne atanamaz.

Nasıl düzeltebilirim? Birlikte nasıl çalışabilir async awaitve Array.mapçalışabilirim?


6
Neden eşzamansız işlemle eşzamanlı işlem yapmaya çalışıyorsunuz? arr.map()zaman uyumludur ve bir söz vermez.
jfriend00

2
Senkronize bir işlev mapbekleyen ve çalışmasını bekleyecek bir işleve eşzamansız bir işlem gönderemezsiniz .
Heretic Maymun

1
@ jfriend00 İç fonksiyonda pek çok bekliyorum. Aslında uzun bir işlev ve onu okunabilir hale getirmek için basitleştirdim. Şimdi neden zaman uyumsuz olması gerektiğini netleştirmek için bir bekleme çağrısı ekledim.
Alon

Dizi döndüren bir şey değil, bir söz veren bir şey beklemeniz gerekir.
jfriend00

2
Gerçekleştirilmesi gereken yararlı bir şey, bir işlevi her işaretlediğinizde async, o işlevi bir söz verdiğiniz anlamına gelir. Tabii ki, bir async haritası bir dizi söz döndürür :)
Anthony Manning-Franklin

Yanıtlar:


382

Burada sorun awaitbir söz yerine bir dizi söz çalışıyoruz . Bu beklediğinizi yapmaz.

İletilen nesne awaitbir Promise olmadığında await, değeri çözmeye çalışmak yerine hemen olduğu gibi döndürür. Bu nedenle await, bir Promise yerine bir dizi (Promise nesneleri) ilettiğiniz için, beklemenin döndürdüğü değer sadece tür olan dizidir Promise<number>[].

Burada yapmanız gereken şey, onu Promise.alldöndürmeden mapönce tek bir Söz'e dönüştürmek için döndürülen diziyi çağırmaktır await.

MDN belgelerinePromise.all göre :

Promise.all(iterable)Yöntem reddeder ilk geçti sözünün nedeni ile giderir iterable argüman sözlerin hepsi çözmüş zaman o bir söz verir veya reddeder.

Yani sizin durumunuzda:

var arr = [1, 2, 3, 4, 5];

var results: number[] = await Promise.all(arr.map(async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
}));

Bu, burada karşılaştığınız hatayı çözecektir.


1
:Sütunlar ne anlama geliyor?
Daniel Reinstate Monica diyor

12
@DanielPendergast TypeScript'teki tür ek açıklamaları içindir.
Ajedi32

Eşzamansız harita işlevi içinde callAsynchronousOperation(item);ve dışında arama yapmak arasındaki fark nedir await?
nerdizzle

@nerdizzle Bu, başka bir soru için iyi bir aday gibi görünüyor. Temel olarak await, işlev devam etmeden önce eşzamansız işlemin tamamlanmasını (veya başarısız olmasını) bekleyecek, aksi takdirde beklemeden hemen devam edecektir.
Ajedi32

@ Ajedi32 cevap için teşekkürler. Fakat eşzamansız haritada beklemeden fonksiyonun sonucunu beklemek artık mümkün değil mi?
nerdizzle

16

Yerel Promises değil Bluebird kullanıyorsanız başka bir çözüm daha var.

Ayrıca , array.map ve Promise.all öğelerini karıştırarak Promise.map () yöntemini kullanmayı deneyebilirsiniz.

Sizin durumunuzda:

  var arr = [1,2,3,4,5];

  var results: number[] = await Promise.map(arr, async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
  });

2
Farklıdır - tüm işlemleri paralel olarak çalıştırmaz, aksine sırayla yürütür.
Andrey Tserkus

5
@AndreyTserkus Promise.mapSeriesveya Promise.eachardışık, Promise.maphepsini bir kerede başlatır.
Kiechlus

1
@AndreyTserkus seçeneğini kullanarak tüm veya bazı işlemleri paralel olarak çalıştırabilirsiniz concurrency.

11
Bir vanilya JS olmadığını belirtmek gerekir.
Michal

@Michal evet, bu SyntaxError
CS QGB


2

Yukarıda belirtildiği gibi Promise.all kullanmanızı tavsiye ederim, ancak bu yaklaşımdan kaçınmak istiyorsanız, bir for veya başka bir döngü yapabilirsiniz:

const arr = [1,2,3,4,5];
let resultingArr = [];
for (let i in arr){
  await callAsynchronousOperation(i);
  resultingArr.push(i + 1)
}

6
Promise.all dizinin her öğesi için zaman uyumsuz olacaktır. Bu bir senkronizasyon olacaktır, bir sonrakini başlatmak için bir öğeyi bitirmek için beklemek zorundadır.
Santiago Mendoza Ramirez

Bu yaklaşımı deneyenler için for..of öğesinin bir dizi içeriğini yinelemenin doğru yolu olduğunu, oysa ..in dizinlerde yinelediğini unutmayın.
ralfoide

2

Bir dizinin tüm öğelerini eşzamansız olarak işlemek VE sırasını korumak için aşağıdaki çözüm:

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 1000));

const calc = async n => {
  await randomDelay();
  return n * 2;
};

const asyncFunc = async () => {
  const unresolvedPromises = arr.map(n => calc(n));
  const results = await Promise.all(unresolvedPromises);
};

asyncFunc();

Ayrıca kodlama .

Dikkat sadece Promise.all için "bekliyor". Birden çok kez "beklemeden" calc diyoruz ve hemen çözülemeyen bir dizi söz topluyoruz. Sonra Promise.all hepsinin çözümlenmesini bekler ve sırayla çözümlenmiş değerlerle bir dizi döndürür.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.