2016-10-19 28 views
48

Biorąc pod uwagę następujący kod:Użyj asynchroniczny czekają z Array.map

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

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

która produkuje następujący błąd:

TS2322: Type 'Promise<number>[]' is not assignable to type 'number[]'. Type 'Promise<number> is not assignable to type 'number'.

Jak mogę to naprawić? Jak mogę sprawić, by async await i Array.map działały razem?

+4

Dlaczego starasz się zrobić synchroniczną pracą w operacji asynchronicznej? 'arr.map()' jest synchroniczne i nie zwraca obietnicy. – jfriend00

+1

Nie można wysłać operacji asynchronicznej do funkcji, takiej jak 'map', która oczekuje synchronicznej i oczekuje, że zadziała. –

+0

@ jfriend00 Mam wiele oczekujących oświadczeń w wewnętrznej funkcji. Jest to w rzeczywistości długa funkcja, którą uprościłem, aby była czytelna. Dodałem teraz oczekujące połączenie, aby wyjaśnić, dlaczego powinien być asynchroniczny. – Alon

Odpowiedz

108

Problem polega na tym, że próbujesz utworzyć tablicę o numerze await. To nie robi tego, czego się spodziewasz.

Gdy obiekt przekazany do await nie jest Obietnicą, po prostu zwraca wartość tak jak jest, zamiast próbować ją rozwiązać. Ponieważ więc zamiast Promise podałeś await tablicę (Obietnica obiektów), wartość zwrócona przez oczekujący jest po prostu tą tablicą, która jest typu Promise<number>[].

Należy tutaj zadzwonić pod numer Promise.all w tablicy zwróconej przez map w celu przekonwertowania go na pojedynczą obietnicę przed await.

Według MDN docs for Promise.all:

The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.

Więc w twoim przypadku:

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; 
})); 

To będzie rozwiązać konkretny błąd jesteś napotykają tutaj.

+0

Co oznaczają '' 'dwukropki? –

+1

@DanielPendergast Jest przeznaczony do adnotacji typu w TypeScript. – Ajedi32

3

Jeśli zamapujesz na tablicę Obietnic, możesz je wszystkie rozłożyć na tablicę liczb. Zobacz Promise.all.

-3

polecam korzystania Promise.all jak wspomniano wyżej, ale jeśli naprawdę poczuć się jak unikać takiego podejścia, można zrobić za lub innej pętli:

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

The Promise.all będzie asynchronizowany dla każdego elementu tablicy. To będzie synchronizacja, musi poczekać na zakończenie jednego elementu, aby rozpocząć następny. –

3

Jest inne rozwiązanie dla niego.

Można również spróbować użyć Promise.map(), mieszanie array.map i Promise.all

W Tobie przypadek:

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

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

Jest inny - nie uruchamia wszystkich operacji równolegle, ale wykonuje je kolejno. –

+1

@AndreyTserkus 'Promise.mapSeries' lub' Promise.każdy z nich jest sekwencyjny, 'Promise.map' uruchamia je wszystkie naraz. – Kiechlus

+0

@AndreyTserkus można uruchamiać wszystkie lub niektóre operacje równolegle, zapewniając opcję 'współbieżności'. –