Node.js geri çağrı piramidi ile başa çıkmak


9

Düğümü kullanmaya yeni başladım ve hızlı bir şekilde fark ettiğim bir şey, geri aramaların ne kadar çabuk aptalca bir girinti seviyesine kadar yükselebileceğidir:

doStuff(arg1, arg2, function(err, result) {
    doMoreStuff(arg3, arg4, function(err, result) {
        doEvenMoreStuff(arg5, arg6, function(err, result) {
            omgHowDidIGetHere();
        });
    });
});

Resmi stil kılavuzu ayrı bir işlevi her geri arama koymak için söylüyor, ama bu nesne tüm geçirilecek zorundadır olarak tek bir nesne, mevcut birkaç katman aşağı üst düzeyde beyan kapanışları kullanımına aşırı kısıtlayıcı görünüyor ve yapım ara geri aramalar.

Burada yardım etmek için işlev kapsamını kullanmak uygun mudur? Global ish nesnesine erişmesi gereken tüm geri çağırma işlevlerini, o nesneyi bildiren bir işlevin içine koyun, böylece kapanmaya gider mi?

function topLevelFunction(globalishObject, callback) {

    function doMoreStuffImpl(err, result) {
        doMoreStuff(arg5, arg6, function(err, result) {
            callback(null, globalishObject);
        });
    }

    doStuff(arg1, arg2, doMoreStuffImpl);
}

ve daha birçok katman için ...

Yoksa her geri arama için adlandırılmış bir işlev bildirmeden girinti düzeylerini azaltmaya yardımcı olacak çerçeveler vb. Var mı? Geri arama piramidiyle nasıl başa çıkıyorsunuz?


2
Kapaklarla ilgili ek sorun olduğunu unutmayın - JS kapatmasında, tüm üst içeriği yakalar (diğer dillerde yalnızca kullanılan değişkeni veya kullanıcının özel olarak istediklerini yakalar), geri arama hiyerarşisi yeterince derinse ve örneğin, geri arama bir yerde tutulur.
Eugene

Yanıtlar:


7

Vaatler, eşzamansız davranış ve arayüz arasındaki endişelerin temiz bir şekilde ayrılmasını sağlar, böylece eşzamansız işlevler geri çağrı olmadan çağrılabilir ve genel vaat arayüzünde geri çağrı etkileşimi yapılabilir.

"Vaatlerin" birden çok uygulaması vardır:


Örneğin, bu iç içe geçmiş geri aramaları yeniden yazabilirsiniz

http.get(url.parse("http://test.com/"), function(res) {
    console.log(res.statusCode);
    http.get(url.parse(res.headers["location"]), function(res) {
        console.log(res.statusCode);
    });
});

sevmek

httpGet(url.parse("http://test.com/")).then(function (res) {
    console.log(res.statusCode);
    return httpGet(url.parse(res.headers["location"]));
}).then(function (res) {
    console.log(res.statusCode);
});

Geri arama geri arama yerine a(b(c()))".then" zincir a().then(b()).then(c()).


Burada bir giriş: http://howtonode.org/promises


bu kaynakların ne yaptığı hakkında daha fazla açıklamayı düşünebilir misiniz ve bunları neden sorulan soruya cevap olarak öneriyorsunuz? "Yalnızca bağlantı yanıtları" Stack Exchange'de pek hoş karşılanmıyor
gnat

1
Tamam üzgünüm. Bir örnek ve daha fazla bilgi ekledim.
Fabien Sa

3

Vaatlere alternatif olarak, yieldanahtar kelimeye EcmaScript 6'da tanıtılacak olan jeneratör işlevleriyle birlikte bakmalısınız. Her ikisi de bugün Node.js 0.11.x derlemelerinde kullanılabilir, ancak --harmonyDüğüm çalıştırırken ek olarak bayrak belirtmenizi gerektirir js:

$ node --harmony app.js

Bu yapıları ve TJ Holowaychuk'un işbirliği gibi bir kütüphaneyi kullanmak , senkronize olmayan bir kodla benzeyen bir tarzda asenkron kodu yazmanıza izin verir , ancak yine de senkronize olmayan bir şekilde çalışır. Temel olarak, bu şeyler birlikte Node.js için eş rutin destek uygular.

Temel olarak, zaman uyumsuz şeyler çalıştıran kod için bir üreteç işlevi yazmak, o zaman zaman uyumsuz şeyler çağırmak, ancak yieldanahtar kelime ile önek . Sonuçta, kodunuz şöyle görünür:

var run = function * () {
  var data = yield doSomethingAsync();
  console.log(data);
};

Bu jeneratör fonksiyonunu çalıştırmak için yukarıda belirtilen işbirliği gibi bir kütüphaneye ihtiyacınız vardır. Çağrı daha sonra şöyle görünür:

co(run);

Veya satır içine koymak için:

co(function * () {
  // ...
});

Lütfen jeneratör fonksiyonlarından diğer jeneratör fonksiyonlarını çağırabileceğinizi, tek yapmanız gereken bunları yieldtekrar önek olarak kullanmak olduğunu unutmayın .

Bu konuya giriş için Google gibi terimleri arayın yield generators es6 async nodejsve tonlarca bilgi bulmalısınız. Alışmak biraz zaman alır, ama bir kez olsun, bir daha geri dönmek istemezsiniz.

Bunun yalnızca işlevleri çağırmak için daha iyi bir sözdizimi sağlamakla kalmayıp, fordöngüler veya try/ gibi olağan (eşzamanlı) kontrol akış mantığı öğelerini kullanmanıza izin verdiğini lütfen unutmayın catch. Artık geri aramalar ve tüm bu şeyler ile uğraşmak yok.

İyi şanslar ve iyi eğlenceler :-)!


0

Artık paket var asyncawait ne olması gerektiğini çok yakın sözdizimi ile, geleceğin doğal destek ve await& asyncDüğümünde.

Temel olarak, senkronize görünümlü asenkron kod yazmanıza , LOC ve girintileme düzeylerini önemli ölçüde azaltmanıza izin verir , hafif bir performans kaybı (paket sahibinin numaraları ham geri aramalara kıyasla% 79 hızdır), yerel destek mevcut olduğunda umarım azalır.

Performans birincil endişe olmadığında ve eşzamanlı yazma stilinin projenizin ihtiyaçlarına daha uygun olduğu durumlarda, geri dönen cehennemden / kıyamet kabus IMO piramidinden çıkmak için hala iyi bir seçim.

Doc paketinden temel örnek:

var foo = async (function() {
    var resultA = await (firstAsyncCall());
    var resultB = await (secondAsyncCallUsing(resultA));
    var resultC = await (thirdAsyncCallUsing(resultB));
    return doSomethingWith(resultC);
});
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.