Próbowałem połączyć ze sobą dwie funkcje asynchroniczne, ponieważ pierwsza miała warunkowy parametr zwrotny, który powodował, że druga albo uruchamiała, albo wychodziła z modułu. Jednak zauważyłem dziwne zachowanie, którego nie mogę znaleźć w specyfikacjach.
async function isInLobby() {
//promise.all([chained methods here])
let exit = false;
if (someCondition) exit = true;
}
To jest zdegradowany fragment mojego kodu (możesz zobaczyć pełny zakres tutaj ), który po prostu sprawdza, czy gracz jest już w lobby, ale to nie ma znaczenia.
Następnie mamy tę funkcję asynchroniczną.
async function countPlayer() {
const keyLength = await scardAsync(game);
return keyLength;
}
Ta funkcja nie musi być uruchamiana, jeśli exit === true
.
Próbowałem to zrobić
const inLobby = await isInLobby();
Miałem nadzieję, że będzie to czekało na wyniki, więc mogę użyć inLobby
do uruchomienia warunkowego countPlayer
, jednak otrzymałem błąd typu bez konkretnych szczegółów.
Dlaczego nie możesz poza funkcją zakresu funkcji? Wiem, że to obietnica cukru, więc musi być przykuta, ale dlaczego w środku mogę czekać na kolejną obietnicę, ale na zewnątrz nie mogę ?await
async
then
countPlayer
await
isInLobby
źródło
await isInLobby()
i jakinLobby
jest używany? Poza tym, gdzie / jak sięcountPlayer
nazywa?isInLobby().then( … countPlayer().then …
części, rozwiązanie jest trywialne: po prostu stwórz funkcję, w której zawarte są te wywołania (tę(req, res) =>
)async
.await
dla swojego kodu? Dlatego zastanawiałem się, że zaakceptowałeś odpowiedź, która tak naprawdę nie dotyczy problemu w pytaniu.Odpowiedzi:
Najwyższy poziom
await
nie jest obsługiwany. Komisja normalizacyjna prowadzi kilka dyskusji na temat przyczyn takiego stanu rzeczy , na przykład ten problem na Githubie .Na Githubie jest też dyskusja na temat tego, dlaczego czekanie na najwyższy poziom to zły pomysł. W szczególności sugeruje, że jeśli masz taki kod:
// data.js const data = await fetch( '/data.json' ); export default data;
Teraz każdy importowany plik
data.js
nie zostanie wykonany przed zakończeniem pobierania, więc całe ładowanie modułu jest teraz zablokowane. To sprawia, że bardzo trudno jest wnioskować o kolejności modułów aplikacji, ponieważ jesteśmy przyzwyczajeni do wykonywania skryptów JavaScript najwyższego poziomu w sposób synchroniczny i przewidywalny. Gdyby było to dozwolone, wiedza, kiedy funkcja zostanie zdefiniowana, staje się trudna.Z mojego punktu widzenia jest to zła praktyka, aby moduł powodował efekty uboczne po prostu ładując go. Oznacza to, że każdy konsument twojego modułu odczuje skutki uboczne po prostu wymagając twojego modułu. To bardzo ogranicza możliwości użycia Twojego modułu. Najwyższy poziom
await
prawdopodobnie oznacza, że czytasz z jakiegoś interfejsu API lub dzwonisz do jakiejś usługi w czasie ładowania. Zamiast tego należy po prostu wyeksportować funkcje asynchroniczne, z których konsumenci mogą korzystać we własnym tempie.źródło
void async function() { const inLobby = await isInLobby() }()
inLobby
funkcji, która czyni ją niedostępną?.then()
(przepraszam, powinienem był to trochę wyjaśnić).Oczywiście jest to zawsze:
(async () => { await ... // all of the script.... })(); // nothing else
To sprawia, że jest to szybka funkcja z async, w której możesz użyć await. Oszczędza to potrzeby tworzenia funkcji asynchronicznej, która jest świetna! // kredyty Silve2611
źródło
await
tej anonimowej funkcji, która znowu nie działa spoza funkcji.Jeszcze lepiej jest umieścić dodatkowy średnik przed blokiem kodu
;(async () => { await ... })();
Zapobiega to automatycznemu formatowaniu (np. W vscode) przeniesieniu pierwszego nawiasu na koniec poprzedniej linii.
Problem można przedstawić na następującym przykładzie:
const add = x => y => x+y const increment = add(1) (async () => { await ... })();
Bez średnika zostanie to ponownie sformatowane jako:
const add = x => y => x+y const increment = add(1)(async () => { await Promise(1) })()
co oczywiście jest błędne, ponieważ przypisuje funkcję asynchroniczną jako
y
parametr i próbuje wywołać funkcję z wyniku (który jest w rzeczywistości dziwnym ciągiem'1async () => {...}'
)źródło
add(1);
funkcji asynchronicznej, a nie przed nią.Od wersji 14.3.0 Node.js obsługiwane jest oczekiwanie najwyższego poziomu.
Wymagane flag
--experimental-top-level-await
.Więcej szczegółów: https://v8.dev/features/top-level-await
źródło
możesz czekać na najwyższy poziom, ponieważ maszynopis 3.8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
Z postu:
To dlatego, że wcześniej w JavaScript (wraz z większością innych języków o podobnej funkcji), await był dozwolony tylko w treści funkcji async. Jednak w przypadku najwyższego poziomu await możemy użyć await na najwyższym poziomie modułu.
const response = await fetch("..."); const greeting = await response.text(); console.log(greeting); // Make sure we're a module export {};
Zauważ, że jest pewna subtelność: najwyższy poziom await działa tylko na najwyższym poziomie modułu, a pliki są uznawane za moduły tylko wtedy, gdy TypeScript znajdzie import lub eksport. W niektórych podstawowych przypadkach może być konieczne napisanie eksportu {} jako szablonu, aby się tego upewnić.
Oczekiwanie najwyższego poziomu może nie działać we wszystkich środowiskach, w których można by się tego spodziewać. Obecnie można używać tylko najwyższego poziomu await, gdy opcja kompilatora docelowego to es2017 lub nowsza, a module to esnext lub system. Wsparcie w kilku środowiskach i pakietach może być ograniczone lub może wymagać włączenia obsługi eksperymentalnej.
źródło