Jeneratörlerle zaman uyumsuz / bekleme ve ES6 verimi arasındaki fark


82

" Jeneratörler" adlı bu harika makaleyi okuyordum ve bu, jeneratör işlevlerini işlemek için yardımcı bir işlev olan bu işlevi açıkça vurgulamaktadır:

function async(makeGenerator){
  return function () {
    var generator = makeGenerator.apply(this, arguments);

    function handle(result){
      // result => { done: [Boolean], value: [Object] }
      if (result.done) return Promise.resolve(result.value);

      return Promise.resolve(result.value).then(function (res){
        return handle(generator.next(res));
      }, function (err){
        return handle(generator.throw(err));
      });
    }

    try {
      return handle(generator.next());
    } catch (ex) {
      return Promise.reject(ex);
    }
  }
}

Varsaydığım, asyncanahtar kelimenin aşağı yukarı async/ ile uygulanma şeklidir await. Öyleyse soru şu, eğer durum buysa, o zaman awaitanahtar kelime ile yieldanahtar kelime arasındaki fark nedir? Her awaitzaman bir şeyi söze dönüştürürken yieldböyle bir garanti vermez mi? Bu benim en iyi tahminim!

Ayrıca , ES7 asenkron işlevlerinin 'spawn' işlevini açıkladığı bu makalede, jeneratörlere nasıl async/ awaitbenzer olduğunu da görebilirsiniz .yield


1
eşzamansız işlev -> bir korutin. generator -> iterator, iç yineleme mekanizmasını yönetmek için bir coroutine kullanır. await, bir eşdizimi askıya alırken, verim, bazı jeneratörlerin kullandığı bir eşgüdümden bir sonuç döndürür
David Haim

1
async/awaitES7'nin bir parçası değildir. Lütfen etiket açıklamasını okuyun.
Felix Kling

@david haim, evet ama async await, jeneratörlerin üzerine inşa edildiğinden farklı değiller
Alexander Mills

Yanıtlar:


46

yieldyapı taşı olarak düşünülebilir await. yieldverilen değeri alır ve arayana iletir. Arayan kişi daha sonra bu değerle (1) dilediğini yapabilir. Arayan, generator.next()daha sonra, yieldifadenin (2) sonucu haline gelen jeneratöre (aracılığıyla ) bir değer verebilir veya yieldifade (3) tarafından atılmış gibi görünecek bir hata verebilir .

async- awaitkullanılması düşünülebilir yield. (1) 'de arayan (yani async- awaitsürücü - gönderdiğiniz işleve benzer) değeri bir sözde benzer bir algoritma kullanarak saracaktır new Promise(r => r(value)(not, değil Promise.resolve , ama bu önemli bir şey değil). Daha sonra sözün çözülmesini bekler. Eğer yerine getirirse, yerine getirilen değeri (2) 'ye geri gönderir. Reddederse, reddetme sebebini (3) 'e hata olarak atar.

Yani faydası async- awaitkullanımları bu makine ise yieldfonksiyon nihai değerini dönünceye kadar tekrar, bir söz olarak vermiştir değeri paketini ve çözülmesi değer sırtını geçmek.


1
Bu argümanla çelişen bu yanıtı stackoverflow.com/a/39384160/3933557 kontrol edin . async-await, verime benzer görünüyor ancak kaputun altında vaatler zinciri kullanıyor. Herhangi bir iyi kaynağınız varsa lütfen paylaşın "async-await, verim olarak değerlendirilebilir".
Samarendra

1
Bu yanıtı nasıl "bu argümanla çelişiyor" olarak değerlendirdiğinizden emin değilim, çünkü bu yanıtla aynı şeyi söylüyor. > Bu arada, Babel gibi aktarıcılar async / await yazmanıza ve kodu jeneratörlere dönüştürmenize izin verir.
Arnavion

Babel, jeneratöre dönüştüğünü söylüyor ama sizin söylediğiniz şey "verim, await'in yapı taşı olarak düşünülebilir" ve "async-await, getiri kullanmak olarak kabul edilebilir." bu benim anlayışıma göre doğru değil (düzeltmeye tabi). async-await, bu yanıtta belirtildiği gibi dahili olarak söz zincirlerini kullanır. Eksik bir şey olup olmadığını anlamak istiyorum, bu konudaki düşüncelerinizi paylaşır mısınız
Samarendra

Bu cevap, tüm dünyadaki tüm ES motorlarının, jeneratörleri kullanarak dahili olarak vaatleri yerine getirdiği iddiasını taşımaz. Bazıları olabilir; bazıları olmayabilir; bunun cevabı olduğu soru ile alakasız. Yine de, işin vaat edilme şekli, jeneratörü çalıştırmanın belirli bir yolu olan jeneratörler kullanılarak anlaşılabilir ve bu yanıtın açıkladığı şey budur.
Arnavion

45

Eh, arasında çok yakın bir ilişki olduğu ortaya çıkıyor async/ awaitve jeneratörler. Ve inanıyorum async/ awaithep jeneratörler üzerine inşa edilecek. Yol bakarsak Babel transpiles async/ await:

Babel şunu alıyor:

this.it('is a test', async function () {

    const foo = await 3;
    const bar = await new Promise(resolve => resolve('7'));
    const baz = bar * foo;
    console.log(baz);

});

ve bunu buna dönüştürür

function _asyncToGenerator(fn) {
    return function () {
        var gen = fn.apply(this, arguments);
        return new Promise(function (resolve, reject) {
            function step(key, arg) {
                try {
                    var info = gen[key](arg);
                    var value = info.value;
                } catch (error) {
                    reject(error);
                    return;
                }
                if (info.done) {
                    resolve(value);
                } else {
                    return Promise.resolve(value).then(function (value) {
                        return step("next", value);
                    }, function (err) {
                        return step("throw", err);
                    });
                }
            }

            return step("next");
        });
    };
}


this.it('is a test', _asyncToGenerator(function* () {   // << now it's a generator

    const foo = yield 3;    //  <<< now it's yield, not await
    const bar = yield new Promise(resolve => resolve(7));
    const baz = bar * foo;
    console.log(baz);

}));

sen hesapla.

Bu, asyncanahtar kelimenin sadece o sarmalayıcı işlevi gibi görünmesini sağlar, ancak durum buysa, o awaitzaman ortaya yieldçıkarsa, daha sonra yerel olduklarında muhtemelen resim biraz daha fazla olacaktır.

Bunun için daha fazla açıklamayı burada bulabilirsiniz: https://www.promisejs.org/generators/


2
NodeJS, bir süredir, jeneratörler olmadan yerel eşzamansız / bekleme özelliğine sahip: codeforgeek.com/2017/02/…
Bram

3
@Bram yerel uygulaması kesinlikle kaputun altındaki jeneratörleri kullanır, aynı şey, sadece soyutlanmış.
Alexander Mills

3
Ben öyle düşünmüyorum. Async / await, V8 motorunda yerel olarak uygulanır. Bir ES6 özelliğinin, eşzamansız / beklemenin ES7 olduğu jeneratörler. Node'da kullanılan V8 motorunun 5.5 sürümünün bir parçasıydı: v8project.blogspot.nl/2016/10/v8-release-55.html . ES7'yi eşzamansız / beklemeyi ES6 jeneratörlerine aktarmak mümkündür, ancak NodeJS'nin yeni sürümleriyle buna artık gerek yoktur ve eşzamansız / bekleme performansı, jeneratörlerden daha iyi görünmektedir: medium.com/@markherhold/…
Bram

1
async / await, işini yapmak için jeneratörler kullanıyor
Alexander Mills

1
@AlexanderMills, async / await'in jeneratörleri dahili olarak kullandığını söyleyen bazı yasal kaynakları paylaşabilir misiniz? bu argümanla çelişen stackoverflow.com/a/39384160/3933557'yi kontrol edin. Bence, sadece Babel jeneratör kullanıyor diye, benzer şekilde kaputun altında uygulandığı anlamına gelmiyor.
Bununla

28

awaitAnahtar kelime ile yieldanahtar kelime arasındaki fark nedir?

awaitAnahtar kelime sadece kullanılacak olan async functionolsa da, s yieldkelime üreteci sadece kullanılacak function*s. Ve bunlar da açıkça farklı - biri vaatleri, diğeri ise üreteçleri döndürüyor.

Her awaitzaman bir şeyi söze dönüştürürken yieldböyle bir garanti vermez mi?

Evet, beklenen değeri awaitarayacak Promise.resolve.

yield sadece jeneratörün dışındaki değeri verir.


Küçük bir nit, ancak cevabımda bahsettiğim gibi, şartname Promise.resolve kullanmıyor (daha önce kullanılıyordu), Promise kurucusu tarafından daha doğru bir şekilde temsil edilen PromiseCapability :: resolve'yi kullanıyor.
Arnavion

@Arnavion: async / await spec'in doğrudan kullandığı ile Promise.resolveaynı new PromiseCapability(%Promise%)şeyi kullanıyor, sadece Promise.resolveanlamanın daha iyi olacağını düşündüm .
Bergi

1
Promise.resolveFazladan bir "IsPromise == true? sonra aynı değeri döndürür" kısa devresine sahiptir. Yani, söz await pnerede ise, pona karar veren p, oysa Promise.resolve(p)geri dönen yeni bir söz verecektir p.
Arnavion

Oh bunu kaçırdım - bunun sadece içinde olduğunu düşündüm Promise.castve tutarlılık nedenleriyle kullanımdan kaldırıldı. Ama önemli değil, zaten bu sözü gerçekten görmüyoruz.
Bergi

2
var r = await p; console.log(r);şunun gibi bir şeye dönüştürülmelidir:, p.then(console.log);ancak pşu şekilde yaratılabilir: var p = new Promise(resolve => setTimeout(resolve, 1000, 42));bu yüzden " bekleme çağrıları Promise.resolve" demek yanlıştır, çağıran "bekle" ifadesinden tamamen uzak başka bir koddur Promise.resolve, dolayısıyla dönüştürülmüş awaitifade yani Promise.then(console.log)çağrılır ve yazdırılır 42.
Dejavu

16

tl; dr

Kullanım async/ awaitjeneratör üzerinde zamanın% 99. Neden?

  1. async/ awaitdoğrudan en yaygın vaat zinciri iş akışının yerini alarak kodun eşzamanlıymış gibi bildirilmesine olanak tanıyarak büyük ölçüde basitleştirir.

  2. Üreteçler, birbirine bağlı olan ve sonunda "tamamlandı" durumunda olacak bir dizi eşzamansız işlemi çağıracağınız kullanım senaryosunu soyutlar. En basit örnek, en sonunda son seti döndüren sonuçlar arasında sayfalama olabilir, ancak bir sayfayı yalnızca gerektiğinde çağırırsınız, hemen arka arkaya değil.

  3. async/ awaitaslında vaatlerle çalışmayı kolaylaştırmak için jeneratörlerin üzerine inşa edilmiş bir soyutlamadır.

Eşzamansız / Bekleme ve Jeneratörlerin Çok Derinlemesine Açıklamasına Bakın


5

Önceden anladığım await/ asyncsözlerle bu test programlarını deneyin .

Program # 1: Sözler olmadan sırayla çalışmaz

function functionA() {
    console.log('functionA called');
    setTimeout(function() {
        console.log('functionA timeout called');
        return 10;
    }, 15000);

}

function functionB(valueA) {
    console.log('functionB called');
    setTimeout(function() {
        console.log('functionB timeout called = ' + valueA);
        return 20 + valueA;
    }, 10000);
}

function functionC(valueA, valueB) {

    console.log('functionC called');
    setTimeout(function() {
        console.log('functionC timeout called = ' + valueA);
        return valueA + valueB;
    }, 10000);

}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

Program # 2: vaatlerle

function functionA() {
    return new Promise((resolve, reject) => {
        console.log('functionA called');
        setTimeout(function() {
            console.log('functionA timeout called');
            // return 10;
            return resolve(10);
        }, 15000);
    });   
}

function functionB(valueA) {
    return new Promise((resolve, reject) => {
        console.log('functionB called');
        setTimeout(function() {
            console.log('functionB timeout called = ' + valueA);
            return resolve(20 + valueA);
        }, 10000);

    });
}

function functionC(valueA, valueB) {
    return new Promise((resolve, reject) => {
        console.log('functionC called');
        setTimeout(function() {
            console.log('functionC timeout called = ' + valueA);
            return resolve(valueA + valueB);
        }, 10000);

    });
}

async function executeAsyncTask() {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
    console.log('response called = ' + response);
});
console.log('program ended');

0

Birçok yönden, jeneratörler async / await'in bir üst kümesidir. Şu anda zaman uyumsuz / bekliyoruz daha temiz yığın izleri vardır işbirliği , en popüler zaman uyumsuz / bekliyoruz benzeri jeneratör bazlı lib. Jeneratörleri kullanarak kendi eşzamansız / yieldbekleme aromanızı uygulayabilir ve söz konusu olmayanlar için yerleşik destek veya RxJS gözlemlenebilirleri üzerinde oluşturma gibi yeni özellikler ekleyebilirsiniz .

Kısacası, jeneratörler size daha fazla esneklik sağlar ve jeneratör tabanlı kitaplıklar genellikle daha fazla özelliğe sahiptir. Ancak async / await, dilin temel bir parçasıdır, standartlaştırılmıştır ve sizin altınızda değişmez ve onu kullanmak için bir kitaplığa ihtiyacınız yoktur. Async / await ve jeneratörler arasındaki fark hakkında daha fazla ayrıntı içeren bir blog yazım var.

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.