Bir zaman uyumsuz işlevin dışında await kullanma


86

İki eşzamansız işlevi birbirine zincirlemeye çalışıyordum, çünkü ilki, ikincisinin çalışmasına veya modülden çıkmasına neden olan bir koşullu dönüş parametresine sahipti. Ancak, özelliklerde bulamadığım garip davranışlar buldum.

async function isInLobby() {
    //promise.all([chained methods here])
    let exit = false;
    if (someCondition) exit = true;
}

Bu kodumun alçakça bir pasajıdır (tam kapsamı burada görebilirsiniz ), bir oyuncunun zaten lobide olup olmadığını kontrol eder, ancak bu alakasızdır.

Daha sonra bu asenkron fonksiyonumuz var.

async function countPlayer() {
    const keyLength = await scardAsync(game);
    return keyLength;
}

Bu işlevin çalıştırılmasına gerek yoktur exit === true.

Yapmaya çalıştım

const inLobby = await isInLobby();

Bunun sonuçları beklemesini umduğum için kullanabilirim inLobby koşullu olarak çalıştırabilirim countPlayer, ancak belirli bir ayrıntı içermeyen bir tür hatası aldım.

Neden işlevin kapsamı dışında awaitbir asyncişlev yapamıyorsunuz ? Bunun şeker sözü olduğunu biliyorum, bu yüzden zincirlenmesi gerekiyor thenama neden countPlayerbaşka bir sözü bekleyebilirim ama dışarıda yapamıyorum await isInLobby?


Bize nerede yaptığınızı await isInLobby()ve nasıl inLobbykullanıldığını gösterebilir misiniz ? Ayrıca nereye / nasıl countPlayerdenir?
Bergi

@Bergi Repo'yu gerçek bağlam için bağladım. Soruya koymak için çok fazla kod
Sterling Archer

Bununla ilgili sorunun nerede olduğunu göremiyorum (belki de depoyu zaten güncellediniz)? Parçaya atıfta bulunursanız isInLobby().then( … countPlayer().then …, çözüm önemsizdir: sadece bu çağrıların bulunduğu işlevi ( (req, res) =>bir) yapın async.
Bergi

@Bergi sorun kırılmış olması değil, olduğu gibi çalışıyor. Sadece üst düzey beklemenin neden bir şey olmadığını anlamadım. Eşzamansız bir işlev olarak tüm modülünüzün kapsamını belirlemeden henüz mevcut olmadığı ortaya çıktı
Sterling Archer

Ama kodunuz için en üst seviyeye bile ihtiyacınız yok awaitmu? Bu yüzden sorudaki sorunla gerçekten ilgisi olmayan cevabı kabul ettiğinizi merak ettim.
Bergi

Yanıtlar:


74

Üst düzey awaitdesteklenmiyor. Bunun neden olduğu konusunda standartlar komitesi tarafından birkaç tartışma var, mesela bu Github sorunu .

Ayrıca Github'da üst düzey beklemenin neden kötü bir fikir olduğuna dair bir düşünce parçası var. Özellikle, böyle bir kodunuz varsa şunları önerir:

// data.js
const data = await fetch( '/data.json' );
export default data;

Artık içe aktarılan herhangi bir dosya data.js, getirme tamamlanıncaya kadar yürütülemeyecek, bu nedenle tüm modül yüklemeniz artık engellenmiştir. Eşzamanlı ve öngörülebilir şekilde üst düzey Javascript yürütmeye alışkın olduğumuzdan, bu uygulama modülü sırası hakkında mantık yürütmeyi çok zorlaştırıyor. Buna izin verildiyse, bir işlevin ne zaman tanımlanacağını bilmek zorlaşır.

Benim bakış açım , modülünüzün sadece onu yükleyerek yan etkilere sahip olmasının kötü bir uygulama olması. Bu, modülünüzün herhangi bir tüketicisinin sadece modülünüzü gerektirerek yan etkilere maruz kalacağı anlamına gelir. Bu, modülünüzün nerede kullanılabileceğini ciddi şekilde sınırlar. En üst düzey, awaitmuhtemelen bazı API'den okuduğunuz veya yükleme sırasında bazı hizmetleri aradığınız anlamına gelir . Bunun yerine, tüketicilerin kendi hızlarında kullanabilecekleri zaman uyumsuz işlevleri dışa aktarmalısınız.


Bu iyi bir bağlantı, teşekkürler. Üst düzey desteğin olmaması utanç verici. Umarım öyledir. Şu anda olduğu gibi sözlerimi buraya yerleştirmem gerekiyor ve bu çok kötü bir uygulama ve bundan hoşlanmıyorum. :( Teşekkürler.
Sterling Archer

@SterlingArcher Alternatif olarak, bir eşzamansız IIFE kullanın:void async function() { const inLobby = await isInLobby() }()
robertklep

@robertklep inLobby, işlevin kapsamını erişilemez hale getirmez mi?
Sterling Archer

@SterlingArcher evet olurdu, tüm kodunuzu oraya taşımanız gerekir (temelde onu "en üst seviye" yapar). Kullanmaya bir alternatif .then()(üzgünüm, bunu biraz daha açık hale getirmeliydim).
robertklep

Kabul etmiyorum, data.js kullanıcısı, data.js'nin kendisini ve tüm bağımlılıklarını yüklerken 'engellenmiş' durumdadır, bu 'engelleme' kavramı kendi başına kötü değildir. üst düzey bekleme, kullanım 'yayımlanmadan' önce görünüşte sahip olması gereken bazı bağımlılıkları yüklemek olarak düşünülebilir.
Ibrahim ben Salah

129

Elbette her zaman şu vardır:

(async () => {
    await ...

    // all of the script.... 

})();
// nothing else

Bu, await'i kullanabileceğiniz zaman uyumsuz hızlı bir işlev yapar. Sizi harika bir zaman uyumsuz işlev yapma ihtiyacından kurtarır! // Silve2611'e kredi verir


3
Lütfen daha fazla ayrıntı verin ve bunun neden işe yaradığını açıklayın.
Paul Back

12
bu yanıta olumsuz oy vermek çok aptalca. Await'i kullanabileceğiniz zaman uyumsuz hızlı bir işlev yapar. Sizi harika bir zaman uyumsuz işlev yapma ihtiyacından kurtarır!
Silve2611

55
Hala awaitbu anonim işleve ihtiyaç duyduğunuz için sorunu çözmez , ki yine işlevlerin dışından çalışmaz.
Michael

peki bu bir hata durumunu nasıl ele alır? ayrıca bekleme kodunun içine mi iniyor?
Manuel Hernandez

Tks this is great help, özellikle geri çağırma sözü, bir kez getItem depolama alanı elde etmek için mükemmel bir şekilde geri yanıt veren oturum açma API'sini getirme sözü için
tess hsu

10

Daha da iyisi, kod bloğunun önüne ek noktalı virgül koymaktır.

;(async () => {
    await ...
})();

Bu, otomatik formatlayıcının (örneğin vscode'da) ilk parantezi önceki satırın sonuna taşımasını engeller.

Sorun aşağıdaki örnekte gösterilebilir:

const add = x => y => x+y
const increment = add(1)
(async () => {
    await ...
})();

Noktalı virgül olmadan, bu şu şekilde yeniden biçimlendirilecektir:

const add = x => y => x+y
const increment = add(1)(async () => {
  await Promise(1)
})()

bu açıkça yanlıştır çünkü zaman uyumsuz işlevi yparametre olarak atar ve sonuçtan bir işlevi çağırmaya çalışır (bu aslında garip bir dizedir '1async () => {...}')


20
Yanlış olan yeniden biçimlendirici değil. Noktalı virgül olmadan, işleviniz çalışma zamanında bu şekilde çözümlenir ve bir hata, satır sonu veya satır sonu almazsınız. Örneğinizdeki doğru çözüm, add(1);zaman uyumsuz işlevden önce değil sonra noktalı virgül eklemektir .
Madara's Ghost

11
Ayrıca, bunun eldeki soruyla nasıl bir ilgisi olduğunu dürüstçe anlamıyorum.
Madara's Ghost

Evet haklısın. Ayrıca çalışma zamanı için noktalı virgül gerekir.
Viliam Simko


1

typecript 3.8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await Posttan
:
Bu, daha önce JavaScript (benzer bir özelliğe sahip diğer dillerin çoğuyla birlikte), await'e yalnızca zaman uyumsuz bir işlevin gövdesi içinde izin verildi. Bununla birlikte, en üst düzey bekleme ile, bir modülün en üst düzeyinde bekleme özelliğini kullanabiliriz.

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};

Bir incelik olduğunu unutmayın: üst düzey bekleme yalnızca bir modülün en üst düzeyinde çalışır ve dosyalar yalnızca TypeScript bir içe aktarma veya dışa aktarma bulduğunda modül olarak kabul edilir. Bazı temel durumlarda, bundan emin olmak için dışa aktar {} 'ı bir standart şablon olarak yazmanız gerekebilir.

Üst düzey bekleme, bu noktada bekleyebileceğiniz tüm ortamlarda çalışmayabilir. Şu anda, yalnızca hedef derleyici seçeneği es2017 veya üstü olduğunda ve modül esnext veya sistem olduğunda üst düzey beklemeyi kullanabilirsiniz. Çeşitli ortamlar ve paketler içindeki destek sınırlı olabilir veya deneysel desteğin etkinleştirilmesini gerektirebilir.

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.