35 Soru: Zaman uyumsuz bir çağrının yanıtını nasıl döndürürüm?

tarafından oluşturulan soru Tue, Feb 26, 2019 12:00 AM

Bir Ajax talebi yapan foo fonksiyonum var. foo’dan gelen yanıtı nasıl iade edebilirim?

success geriçağırımının değerini döndürmenin yanı sıra, işlev içindeki yerel bir değişkene yanıt atama ve bunu döndürmeyi denedim, ancak bu yöntemlerin hiçbiri yanıtı geri döndürmedi.

 
function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.
    
4982
  1. Sözler'e basit bir giriş yapmak için, bu iyi bir okuma olabilir: devopedia.org/promises
    2018-02-14 09: 20: 09Z
  2. [Eşzamanlı bir işlev kullanmanız önerilmez, ancak bazı durumlar için işe yarar olsa da, aynı anda asenkron çağrı ile karşı karşıya kalıyordum. ] ( stackoverflow.com/questions/55239719/… ) çağrısı yapıyor
    2019-04-10 14: 15: 35Z
  3. İstediğiniz şekilde çalışmasını sağlayamazsınız. Ancak, zaman uyumsuz /bekler işe yarayacak. yine söz tabanlıdır
    2019-05-22 15: 04: 36Z
30 Yanıtlar                              30                         
  

→ Farklı örneklerle eşzamansız davranışın daha genel bir açıklaması için, lütfen bkz. Değişkenim neden değiştirilmemiş? bir fonksiyonun içinde değiştirdikten sonra mı? - Eşzamansız kod başvurusu

     

→ Sorunu daha önce anladıysanız, aşağıdaki olası çözümlere atlayın.

Sorun

Ajax 'daki A , eşzamansız . Bu, isteğin gönderilmesi (veya daha doğrusu yanıtın alınması) normal uygulama akışından alındığı anlamına gelir. Örnekte, $.ajax derhal geri döner ve return result; adlı sonraki deyim, success geri arama bile çağrıldığınız işlevden önce yürütülür.

İşte, senkronize ve senkronize olmayan akış arasındaki farkı daha net bir şekilde açıklayan bir benzetme:

Senkron

Bir arkadaşınıza bir telefon görüşmesi yaptığınızı ve ondan sizin için bir şey aramasını istediğinizi hayal edin. Biraz zaman alabilir, ancak arkadaşınız size gereken cevabı verene kadar telefonda bekleyin ve uzaya bakın.

"Normal" kod içeren bir işlev çağrısı yaparken de aynı şey olur:

 
function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

findItem'un yürütülmesi uzun zaman alsa da, var item = findItem();'dan sonra gelen herhangi bir kod, işlev sonucu döndürene kadar beklemelidir .

Asenkron

Aynı sebepten dolayı arkadaşını tekrar ara. Ama bu sefer ona acelesi olduğunu ve cep telefonundan seni geri çağırması olduğunu söyledin. Telefonu kapat, evden ayrıl ve ne yapmayı planlıyorsan onu yap. Arkadaşınız sizi geri aradığında, size verdiği bilgilerle uğraşıyorsunuz.

Ajax isteğinde bulunduğunuzda olan tam olarak bu.

 
findItem(function(item) {
    // Do something with item
});
doSomethingElse();

Yanıtı beklemek yerine, yürütme derhal devam eder ve Ajax çağrısından sonraki ifade. Sonunda yanıtı almak için, yanıt alındıktan sonra çağrılacak bir işlev, geri arama (bir şey fark eder misiniz? geri arama ?) Sağlarsınız. Bu çağrıdan sonra gelen herhangi bir ifade, geri arama çağrılmadan önce yürütülür.


Çözüm (ler)

JavaScript’in eşzamansız yapısını benimseyin! Bazı eşzamansız işlemler eşzamanlı meslektaşları sağlarken ("Ajax" da), genel olarak bunları özellikle tarayıcı bağlamında kullanmaktan kaçınır.

Neden soruyorsun kötü?

JavaScript, tarayıcının UI iş parçacığında çalışır ve uzun süren herhangi bir işlem kullanıcı arabirimini kilitleyerek yanıt vermez. Ek olarak, JavaScript yürütme süresinde bir üst sınır vardır ve tarayıcı kullanıcıya soracaktır.Yürütmeye devam edip etmemek.

Bütün bunlar gerçekten kötü bir kullanıcı deneyimi. Kullanıcı her şeyin yolunda olup olmadığını söyleyemez. Ayrıca, yavaş bağlantıya sahip kullanıcılar için bu etki daha da kötüleşecek.

Aşağıda, her biri üst üste inşa edilmiş üç farklı çözüme bakacağız:

  • async/await ile vaat ediyor (bir aktarıcı veya rejeneratör kullanıyorsanız ES2017 +, eski tarayıcılarda kullanılabilir)
  • Geri aramalar (düğümde popüler)
  • Pek çok söz veren kütüphaneden birini kullanıyorsanız, then() ile vaat eden (ES2015 +, eski tarayıcılarda kullanılabilir)

Her üçü de mevcut tarayıcılarda ve düğüm 7 + 'da kullanılabilir.


ES2017 +: async/await ile vaat ediyor

2017'de piyasaya sürülen ECMAScript sürümü, zaman uyumsuz işlevler için sözdizimi düzeyinde destek uygulamasına neden oldu. async ve await'un yardımıyla "senkronize bir tarzda" zaman uyumsuz yazabilirsiniz. Kod hala eşzamansızdır ancak okunması /anlaşılması daha kolaydır.

async/await, sözler üzerine kuruludur: async işlevi her zaman bir söz verir. await bir vaadi "çözer" ve ya vaadin çözüldüğü değerle sonuçlanır ya da söz reddedilirse bir hata yapar.

Önemli: Bir await işlevinde yalnızca async kullanabilirsiniz. Şu anda, en üst düzey await henüz desteklenmiyor, bu nedenle bir zaman uyumsuz IIFE yapmak zorunda kalabilirsiniz ( Derhal Davet Edilmedi) İşlev İfadesi ) async içerik başlatmak için.

async hakkında daha fazla bilgi edinebilirsiniz. ve MDN’de await .

İşte yukarıdaki gecikmenin üstüne çıkan bir örnek:

 
// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Start an IIFE to use `await` at the top level
(async function(){
  let books = await getAllBooks();
  console.log(books);
})();

Geçerli tarayıcı ve düğüm sürümleri async/await'u destekler. Ayrıca, rejeneratör (veya rejeneratör kullanan araçlar) yardımıyla kodunuzu ES5’e dönüştürerek daha eski ortamları da destekleyebilirsiniz. , örneğin, Babel ).


İşlevlerin geri aramaları kabul etmesine izin verin

Geri arama, yalnızca başka bir işleve geçirilen bir işlevdir. Diğer işlev, hazır olduğunda, geçirilen işlevi çağırabilir. Zaman uyumsuz bir işlem bağlamında, zaman uyumsuz işlem yapıldığında geri çağrı çağrılır. Genellikle, sonuç geri aramaya aktarılır.

Soru örneğinde, foo'un geri arama kabul etmesini sağlayabilir ve success geri arama olarak kullanabilirsiniz. Yani bu

 
var result = foo();
// Code that depends on 'result'

olur

 
foo(function(result) {
    // Code that depends on 'result'
});

Burada "satır içi" işlevini tanımladık, ancak herhangi bir işlev başvurusunu iletebilirsiniz:

 
function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo’un kendisi şu şekilde tanımlanmıştır:

 
function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback, onu aradığımızda foo'a geçirdiğimiz işlevi ifade eder ve basitçe success'a geçiririz. Yani Ajax talebi başarılı olduktan sonra $.ajax, callback'u arayacak ve geri aramayı yanıtlayacaktır (result ile belirtilebilir, çünkü geri aramayı bu şekilde tanımladık).

Yanıtı geri aramaya aktarmadan önce de işleyebilirsiniz:

 
function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

Geri aramaları kullanarak kod yazmak göründüğünden daha kolaydır. Ne de olsa, tarayıcıdaki JavaScript büyük oranda olay odaklı (DOM olayları). Ajax yanıtını almak bir olaydan başka bir şey değildir.
Üçüncü taraf kodlarıyla çalışmak zorunda olduğunuzda zorluklar ortaya çıkabilir, ancak çoğu sorun yalnızca uygulama akışını düşünerek çözülebilir.


ES2015 +: sonra () ile vaat ediyor >

API Promise API yeni bir şey ECMAScript 6 (ES2015) 'nin özelliği ancak önceden tarayıcı desteği var. Standart Promises API'sini uygulayan ve asenkron fonksiyonların kullanımını ve bileşimini kolaylaştırmak için ek yöntemler sunan birçok kitaplık da vardır (örn. bluebird ).

Sözler, gelecek değerler için kapsayıcıdır. Söz verdiğimiz değeri aldığında ( çözüldü ) veya iptal edildiğindeled ( reddedildi ), bu değere erişmek isteyen tüm "dinleyicilerini" bildirir.

Düz geri aramalara göre avantajı, kodunuzu eklemenizi sağlamaları ve oluşturmaları daha kolay olmasıdır.

İşte size söz vermenin basit bir örneği:

 
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected 
    // (it would not happen in this example, since `reject` is not called).
  });

Ajax çağrımıza uygulandığında şöyle sözler kullanabiliriz:

 
function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

Teklif vaat eden tüm avantajları açıklamak, bu cevabın kapsamı dışındadır, ancak yeni bir kod yazarsanız, bunları ciddi şekilde düşünmelisiniz. Kodunuzun mükemmel bir soyutlamasını ve ayrılmasını sağlarlar.

Sözler hakkında daha fazla bilgi: HTML5 rocks - JavaScript Sözleri

Yan not: jQuery'nin ertelenen nesneleri

Ertelenen nesneler , jQuery'nin sözlerin özel uygulamasıdır (Promise API'sinin standartlaştırılmasından önce). Neredeyse vaat ettikleri gibi davranıyorlar ancak biraz farklı bir API ortaya koyuyorlar.

Her jQuery'deki Ajax yöntemi zaten işlevinizden döndürebileceğiniz bir "ertelenmiş nesne" (aslında ertelenmiş bir nesnenin vaadi) döndürür:

 
function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Yan not: Alınanlara söz ver

Gelecekteki bir değer için vaat ve ertelenen nesnelerin yalnızca kapsayıcılar olduğunu, değerin kendisi olmadığını unutmayın. Örneğin, şunlara sahip olduğunuzu varsayalım:

 
function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

Bu kod yukarıdaki eşzamansız sorunları yanlış anlar. Özellikle, $.ajax() sunucunuzdaki '/password' sayfasını kontrol ederken kodu dondurmaz; sunucuya bir istek gönderir ve beklerken sunucudan gelen yanıtı değil hemen bir jQuery Ajax Deferred nesnesini döndürür. Bu, if ifadesinin bu Ertelenen nesneyi her zaman alacağı, true olarak kabul edeceği ve kullanıcı giriş yapmış gibi devam edeceği anlamına gelir.

Ancak düzeltme kolaydır:

 
checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

Tavsiye edilmez: Senkron "Ajax" çağrıları

Bahsettiğim gibi, bazı (!) eşzamansız işlemlerin eşzamanlı benzerleri vardır. Kullanımlarını savunmuyorum, ancak bütünlük uğruna, nasıl senkronize bir arama yapacağınız:

jQuery olmadan

Doğrudan bir XMLHTTPRequest nesnesini kullanıyorsanız, false'u .open .

jQuery

jQuery kullanıyorsanız, async seçeneğini false olarak ayarlayabilirsiniz. JQuery 1.8’den bu yana kullanımdan kaldırıldığını unutmayın. Daha sonra hala bir success geri arama kullanabilir veya jqXHR nesnesinin responseText özelliğine erişebilirsiniz :

 
function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

$.get, $.getJSON vb. gibi başka bir jQuery Ajax yöntemi kullanırsanız, bunu $.ajax olarak değiştirmeniz gerekir (çünkü yapılandırma parametrelerini yalnızca $.ajax olarak geçirebilirsiniz).

Başlarken! Eşzamanlı yapmak mümkün değildir JSONP istek. JSONP, doğası gereği, her zaman asenkrondir (bu seçeneği düşünmemek için bir neden daha vardır).

    
5282
2019-03-03 17: 28: 08Z
  1. @ Pommy: jQuery kullanmak istiyorsanız, eklemeniz gerekir. Lütfen docs.jquery.com/Tutorials:Getting_Started_with_jQuery adresine bakın.
    2013-01-17 10: 47: 54Z
  2. Çözüm 1'de, alt jQuery'de, bu satırı anlayamadım: If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax. (Evet, nickimin bu durumda biraz ironik olduğunun farkındayım)
    2013-02-06 21: 07: 03Z
  3. @ gibberish: Mmmh, nasıl daha açık hale getirilebileceğini bilmiyorum. foo'un nasıl çağrıldığını ve ona bir fonksiyonun geçtiğini görüyor musunuz (foo(function(result) {....});)? result bu fonksiyon içerisinde kullanılır ve Ajax isteğinin cevabıdır. Bu işleve atıfta bulunmak için, foo'nun ilk parametresi callback olarak adlandırılır ve adsız bir işlev yerine success'a atanır. Böylece, istek başarılı olduğunda $.ajax, callback'u arayacaktır. Bunu biraz daha açıklamaya çalıştım.
    2013-02-06 23: 29: 52Z
  4. Bu soru için sohbet öldü, bu yüzden nerede özetlenen chang'i önereceğimi bilmiyorumes, ancak şunu öneriyorum: 1) Eşzamanlı kısmı, bunun nasıl yapılacağına dair bir kod örneği olmadan niçin kötü olduğunu basit bir tartışmayla değiştirin. 2) Yalnızca daha esnek olan Ertelenmiş yaklaşımı göstermek için geri arama örneklerini kaldırın /birleştirin. Javascript öğrenenlerin takip etmesi biraz daha kolay olabilir diye düşünüyorum.
    2013-04-16 02: 45: 22Z
  5. @ Jessi: Sanırım cevabın bu bölümünü yanlış anladınız. Ajax isteğinin senkronize olmasını istiyorsanız, $.getJSON'u kullanamazsınız. Ancak, isteğin senkronize olmasını istemelisiniz, bu nedenle geçerli değildir. Cevabın başlarında açıklandığı gibi yanıtı ele almak için geri aramalar veya sözler kullanıyor olmalısınız.
    2015-10-08 17: 44: 18Z

Kodunuzda jQuery kullanıyorsanız kullanmıyorsanız , bu cevap sizin için

Kodunuz, bu satırlar boyunca bir şey olmalıdır:

 
function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Felix Kling, AJAX için jQuery kullanan kişilere cevap yazma konusunda iyi bir iş yaptı, olmayan insanlar için bir alternatif sunmaya karar verdim.

( Yeni fetch API’yı kullananlar için, aşağıda Asgular veya başka bir cevap eklediğim sözler )

/p>


Karşılaştığınız şey

Bu, diğer sorunun yazdığı "Sorunun açıklaması" nın kısa bir özetidir, eğer bunu okuduktan sonra emin değilseniz, bunu okuyun.

AJAX’taki A , eşzamansız anlamına gelir. Bu, isteğin gönderilmesi (veya daha doğrusu yanıtın alınması) normal uygulama akışından alındığı anlamına gelir. Örnekte, .send hemen dönüyor ve return result; adlı sonraki ifade, success geri arama olarak geçirdiğiniz işlevden bile önce çağrılıyor.

Bu, geri döndüğünüzde, tanımladığınız dinleyicinin henüz çalışmadığı, yani döndürdüğünüz değerin tanımlanmadığı anlamına gelir.

İşte basit bir benzetme

 
function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

a kısmı henüz uygulanmadığından, undefined değeri a=5'dur. AJAX bu şekilde davranır, sunucu tarayıcınıza bu değerin ne olduğunu söyleme şansını yakalamadan önce değeri döndürürsünüz.

Bu soruna olası bir çözüm, kodunu yeniden etkin bir şekilde kodlamak ve hesaplama tamamlandığında programınıza ne yapacağınızı bildirmektir.

 
function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

Buna CPS denir. Temel olarak, getFive'u tamamlandığında gerçekleştirecek bir eylemden geçiyoruz, kodumuza bir etkinlik tamamlandığında nasıl bir tepki vereceğimizi (AJAX çağrımız gibi veya bu durumda zaman aşımı gibi) söylüyoruz.

Kullanım şöyle olur:

 
getFive(onComplete);

Ekrana "5" uyarısı vermesi gerekenler. (Fiddle) .

Muhtemel çözümler

Bunu çözmenin temelde iki yolu vardır:

  1. AJAX aramasını senkronize edin (SJAX olarak adlandıralım).
  2. Geri aramalarla düzgün çalışacak şekilde kodunuzu yeniden yapılandırın.

1. Senkron AJAX - Yapmayın !!

Senkron AJAX'a gelince, yapmayın! Felix'in cevabı neden kötü bir fikir olduğu konusunda bazı zorlayıcı argümanlar ortaya koyuyor. Özetlemek gerekirse, sunucu yanıtı döndürene ve çok kötü bir kullanıcı deneyimi yaratana kadar kullanıcının tarayıcısını dondurur. İşte MDN'den neden aldığımız bir başka kısa özeti:

  

XMLHttpRequest, hem senkron hem de asenkron iletişimleri destekler. Ancak, genel olarak, zaman uyumsuz isteklerin, performans nedenlerinden dolayı zaman uyumlu isteklere tercih edilmesi gerekir.

     

Kısaca, senkronize istekler, kodun yürütülmesini engeller ... ... bu ciddi sorunlara neden olabilir ...

Yapmanız gereken varsa, bir bayrak iletebilirsiniz: İşte nasıl:

 
var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. Yeniden yapılandırma kodu

İşlevinizin geri arama kabul etmesine izin verin. Örnekte foo kodu bir geri aramayı kabul etmek için yapılabilir. foo tamamlandığında kodumuza nasıl tepki vereceğimizi söyleyeceğiz.

Yani:

 
var result = foo();
// code that depends on `result` goes here

Oldu:

 
foo(function(result) {
    // code that depends on `result`
});

Burada anonim bir işlevi geçtik, ancak varolan bir işleve bir referansı kolayca ileterek şöyle görünmesini sağladık:

 
function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

Bu tür bir geri arama tasarımının nasıl yapıldığına dair daha fazla ayrıntı için Felix'in yanıtını kontrol edin.

Şimdi, foo'nun rolünü tanımlayalım.buna göre

 
function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(keman)

Artık foo fonksiyonumuzu AJAX başarıyla tamamlandığında çalıştırılacak bir eylemi kabul ettirdik, yanıt durumunun 200 olup olmadığını kontrol ederek ve buna göre davranarak bunu daha da uzatabiliriz (bir başarısız işleyici ve benzeri yaratırız). Sorunumuzu etkin bir şekilde çözme.

Bunu anlamakta hala zorlanıyorsanız, AJAX'ın başladığını okuyun MDN'deki kılavuz .

    
1017
2018-03-01 01: 03: 52Z
  1. "eşzamanlı istekler kod yürütülmesini engeller ve hafıza ve olaylara sızıntı yapabilir" eşzamanlı bir istekte hafıza nasıl sızıntı yapabilir?
    2013-08-16 05: 54: 22Z
  2. @ MatthewG bu soruyu , ne balık tutabileceğimi göreceğim. Teklifi ortalama süre içinde yanıttan kaldırıyorum.
    2013-08-16 08: 28: 00Z
  3. Sadece referans için, XHR 2, yalnızca onload readyState olduğunda çalışan 4 işleyiciyi kullanmamıza izin veriyor. Tabii ki, IE8'de desteklenmiyor. (iirc, onaylanması gerekebilir.)
    2013-12-22 21: 09: 19Z
  4. Adsız bir işlevin bir geri çağırma olarak nasıl geçileceğine dair açıklamanız geçerli ama yanıltıcıdır. Örnek var bar = foo (); tanımlanacak bir değişken istiyor, oysa önerilen foo (functim () {}); çubuğu tanımlamıyor
    2014-08-07 10: 14: 22Z
  5. @ BenjaminGruenbaum result'un içeriğini html ile yazdırmak yerine kodumda başka bir yerde kullanabileceğim bir değişkende nasıl döndürürüm?
    2016-11-08 15: 39: 44Z

XMLHttpRequest 2 (her şeyden önce yanıtları okuyun a href = "https://stackoverflow.com/a/16825593/19068"> Benjamin Gruenbaum & Felix Kling )

Eğer jQuery kullanmıyorsanız ve modern tarayıcılarda ve ayrıca mobil tarayıcılarda çalışan kısa bir XMLHttpRequest 2 istiyorsanız, bu şekilde kullanmanızı öneririm:

 
function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

Gördüğünüz gibi:

  1. Listelenen diğer tüm işlevlerden daha kısa.
  2. Geri arama doğrudan ayarlanır (bu yüzden fazladan fazladan kapatma gerekmez).
  3. Yeni yükü kullanır (bu nedenle, okuma istasyonu ve amper durumunu kontrol etmeniz gerekmez)
  4. XMLHttpRequest 1'i sinirlendiren, hatırlamadığım başka durumlar da var.

Bu Ajax çağrısının yanıtını almanın iki yolu vardır (üçü XMLHttpRequest var adını kullanarak):

En basiti:

 
this.response

Veya, bir nedenden dolayı bir sınıfa geri çağırma bind():  

e.target.response

Örnek:

 
function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

Veya (yukarıdakilerden daha iyisi anonim işlevler her zaman bir problemdir):

 
ajax('URL', function(e){console.log(this.response)});

Daha kolay bir şey yok.

Şimdi bazı insanlar muhtemelen onreadystatechange'i veya hatta XMLHttpRequest değişken adını kullanmanın daha iyi olacağını söyleyecekler. Bu yanlış.

XMLHttpRequest gelişmiş özelliklerine göz atın

Tüm modern tarayıcıları destekledi. XMLHttpRequest 2 var olduğundan beri bu yaklaşımı kullandığımı doğrulayabilirim. Kullandığım tüm tarayıcılarda hiçbir zaman herhangi bir sorun yaşamadım.

onreadystatechange yalnızca başlıkları 2 durumuna almak istiyorsanız kullanışlıdır.

XMLHttpRequest değişken adının kullanılması, başka bir büyük hatadır, çünkü geri yüklediğiniz, aşırı yük /oreadystatechange kapanışları içinde geri çağırmayı uygulamanız gerekir.


Artık post ve FormData kullanarak daha karmaşık bir şey istiyorsanız, bu işlevi kolayca genişletebilirsiniz:

 
function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

Yine ... bu çok kısa bir işlev, ancak elde ediyor & Mesaja.

Kullanım örnekleri:

 
x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

Veya tam bir form öğesini (document.getElementsByTagName('form')[0]) iletin:

 
var fd = new FormData(form);
x(url, callback, 'post', fd);

Veya bazı özel değerler belirleyin:

 
var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

Gördüğünüz gibi uygulayamadıment sync ... bu kötü bir şey.

Bunu söyledikten sonra ... neden kolay yoldan yapmıyorsun?


Yorumda belirtildiği gibi, hata kullanımı & & senkron, cevabın tamamen kırılmasını sağlar. Ajax'ı uygun şekilde kullanmak için güzel bir kısa yol hangisidir?

Hata işleyici

 
function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

Yukarıdaki komut dosyasında, statik olarak tanımlanmış olan ve işlevden ödün vermeyen bir hata işleyiciniz vardır. Hata işleyicisi diğer işlevler için de kullanılabilir.

Ancak gerçekten bir hata almak için yalnızca yöntem, yanlış bir URL yazmaktır; bu durumda her tarayıcı bir hata atar.

Özel başlıklar ayarladıysanız, yanıt türünü blob dizi arabelleğine ya da her ne olursa olsun ayarladıysanız, hata işleyicileri yararlı olabilir ...

'POSTAPAPAP' seçeneğini yöntem olarak geçseniz bile hata atmaz.

'fdggdgilfdghfldj' formdata olarak geçseniz bile hata vermez.

İlk durumda, hata displayAjax()’un this.statusText’da Method not Allowed’un altındadır.

İkinci durumda, sadece işe yarar. Doğru gönderi verilerinden geçip geçmediğinizi sunucu tarafında kontrol etmeniz gerekir.

etki alanları arası alana izin verilmiyor otomatik olarak hata veriyor.

Hata yanıtında hata kodu yok.

Yalnızca this.type hataya ayarlanmış.

Hatalar üzerinde tamamen kontrolünüz yoksa neden bir hata işleyicisi ekleyin? Hataların çoğu, displayAjax() geri arama işlevinde bunun içinde döndürülür.

Öyleyse: URL’yi düzgün bir şekilde kopyalayıp yapıştırabiliyorsanız hata kontrollerine gerek yoktur. ;)

PS: İlk test olarak x ('x', displayAjax) yazdım ... ve tamamen bir yanıt aldı ... ??? Böylece HTML'nin bulunduğu klasörü kontrol ettim ve 'x.xml' adında bir dosya vardı. Bu nedenle, dosyanızın uzantısını unutsanız bile XMLHttpRequest 2 WILL FIND IT . YAŞAMIYORUM


Eşit bir dosyayı okuyun

Bunu yapma.

Tarayıcıyı bir süre engellemek istiyorsanız, güzel bir .txt dosya senkronize edin.

 
function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

Şimdi yapabilirsiniz

 
 var res = omg('thisIsGonnaBlockThePage.txt');

Bunu asenkronize olmayan bir şekilde yapmanın başka bir yolu yoktur. (Evet, setTimeout döngüsüyle ... ama cidden?)

Başka bir nokta şudur: API'larla veya yalnızca kendi listenizin dosyalarıyla çalışıyorsanız veya her bir istek için her zaman farklı işlevleri kullanırsanız ...

Yalnızca her zaman aynı XML /JSON'u yüklediğiniz bir sayfanız veya yalnızca bir işleve ihtiyacınız olan bir sayfanız varsa. Bu durumda, biraz Ajax işlevini değiştirin ve b'yi özel işlevinizle değiştirin.


Yukarıdaki işlevler temel kullanım içindir.

Fonksiyonu genişletmek istiyorsanız ...

Evet, yapabilirsiniz.

Çok fazla API kullanıyorum ve her HTML sayfasına entegre ettiğim ilk işlevlerden biri bu cevaptaki ilk Ajax işlevidir, yalnızca GET ile ...

Ancak XMLHttpRequest 2: ile birçok şey yapabilirsiniz:

Bir indirme yöneticisi yaptım (her iki tarafta da özgeçmiş, filereader, dosya sistemi ile aralıkları kullanarak), tuval kullanarak çeşitli görüntü boyutlandırıcıları dönüştürücüler, base64images içeren web SQL veritabanlarını doldurmak ve çok daha fazlası ... Ancak bu durumlarda bir işlev oluşturmalısınız yalnızca bu amaç için ... bazen bir blob'a, dizi arabelleğine ihtiyacınız olabilir, üstbilgileri ayarlayabilir, mime tipini geçersiz kılabilir ve daha birçok şey olabilir ...

Ancak buradaki soru, bir Ajax yanıtını nasıl iade edeceğimiz ... (Kolay bir yol ekledim.)

    
372
2018-12-10 09: 08: 05Z
  1. Bu cevap güzel olsa da (Ve hepimiz aşk XHR2 ve dosya verilerini ve çok parçalı verileri gönderme tamamen harikadır) - bu, sözdizimsel şekeri gösterir. XHR'yi JavaScript ile yayınlamak - bunu bir blog postasına (isterdim) ya da bir kütüphaneye koymak isteyebilirsiniz (x, ajax veya xhr adından daha iyi olabilir :)). Bir AJAX çağrısından gelen yanıtın nasıl yanıtlandığını ele almıyorum. (birisi hala var res = x("url")'u yapabilir ve neden işe yaramadığını anlayamaz;)). Bir yandan notta - kullanıcıların c'u bu yöntemle alabilmesi için error'u geri döndürmeniz harika olurdu.
    2013-08-23 05: 56: 49Z
  2. 2.ajax is meant to be async.. so NO var res=x('url').. Bu soru ve cevapların esas noktası budur :)
    2013-08-23 17: 28: 35Z
  3. işlevlerde neden bir 'c' parametresi var, eğer ilk satırda sahip olduğu değerin üzerine yazarsanız? bir şey mi eksik?
    2016-12-21 10: 00: 52Z
  4. Birden çok ti yazmaktan kaçınmak için parametreleri yer tutucu olarak kullanabilirsinizmes "var"
    2016-12-21 11: 05: 21Z
  5. @ cocco Böylece birkaç tuşa basmak için SO cevabını yanıltıcı, okunamayan bir kod mu yazdınız? Lütfen bunu yapma.
    2017-10-08 06: 20: 55Z

Eğer söz kullanıyorsanız, bu cevap tam size göre.

Bu, AngularJS, jQuery (ertelenmiş), yerel XHR’nin değiştirilmesi (getirme), EmberJS, BackboneJS’in kaydetmesi veya söz veren herhangi bir düğüm kitaplığı anlamına gelir.

Kodunuz, bu satırlar boyunca bir şey olmalıdır:

 
function foo() {
    var data;
    // or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // result is always undefined no matter what.

Felix Kling, jQuery kullanan kişilere AJAX için geri aramaları olan bir cevap yazarken iyi bir iş yaptı. Yerel XHR için bir cevabım var. Bu cevap sözlerin ya ön uçta ya da arka uçta genel kullanımı içindir.


Temel sorun

Tarayıcıdaki ve NodeJS /io.js dosyasının bulunduğu sunucudaki JavaScript eşzamanlılık modeli asenkron ve reaktif .

Ne zaman söz veren bir yöntem çağırırsanız, then işleyicileri her zaman eşzamansız olarak yürütülür - yani, altındaki .then işleyicide olmayan kodların ardından .

Bu, tanımladığınız data işleyiciyi then’a döndürdüğünüzde henüz çalışmadı. Bu da, döndürdüğünüz değerin zaman içinde doğru değere ayarlanmadığı anlamına gelir.

Sorunla ilgili basit bir benzetme:

 
    function getFive(){
        var data;
        setTimeout(function(){ // set a timer for one second in the future
           data = 5; // after a second, do this
        }, 1000);
        return data;
    }
    document.body.innerHTML = getFive(); // `undefined` here and not 5

data kısmı henüz uygulanmadığından undefined değeri data = 5'dur. Büyük olasılıkla bir saniye içinde gerçekleşecek, ancak o zamana kadar iade edilen değer ile ilgisi yok.

İşlem henüz gerçekleşmedi (AJAX, sunucu çağrısı, G /Ç, zamanlayıcı), istekte bulunmadan önce değeri döndürüyorsunuz, kodunuza bu değerin ne olduğunu söyleme şansı yakaladı.

Bu sorunun olası bir çözümü, kodunu yeniden etkin bir şekilde kodlamak ve hesaplama tamamlandığında programınıza ne yapacağınızı bildirmektir. Sözler, doğada zamansal (zamana duyarlı) olarak bunu aktif bir şekilde sağlar.

Vaatlerde hızlı özetleme

Bir Söz, zaman içindeki bir değeridir . Sözler devlete sahip, hiçbir değeri olmadan beklemeye başlıyorlar ve buna razı olabilirler:

  • tamamlandı , hesaplamanın başarıyla tamamlandığı anlamına gelir.
  • reddedildi , hesaplamanın başarısız olduğu anlamına gelir.

Bir söz, yalnızca bir kez durumlarını değiştirebilir; bundan sonra daima aynı durumda kalır. Değerlerini almak ve hataları ele almak için then işleyicileri ekleyebilirsiniz. then işleyicileri aramaların zincirlemeye izin veriyor. Sözler, kendilerine geri dönen API’ları kullanarak tarafından oluşturulmaktadır. >. Örneğin, daha modern AJAX yedek fetch veya jQuery'nin $.get modelinin dönüş vaadi.

Bir söz verdiğimizde .then'u aradığımızda ve geri döndüğümüzde bir şey alırsak - işlenen değer için bir söz alırız. Başka bir söz verirsek harika şeyler elde ederiz, ama atlarımızı tutalım.

Sözlerle

Yukarıdaki konuyu vaatlerle nasıl çözebileceğimizi görelim. Öncelikle, Bir gecikme işlevi oluşturmak için yapıcıya söz verin :

 
function delay(ms){ // takes amount of milliseconds
    // returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // when the time is up
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

Şimdi, setTimeout'u sözleri kullanmaya dönüştürdükten sonra, then'u saymak için kullanabiliriz:

 
function delay(ms){ // takes amount of milliseconds
  // returns a new promise
  return new Promise(function(resolve, reject){
    setTimeout(function(){ // when the time is up
      resolve(); // change the promise to the fulfilled state
    }, ms);
  });
}

function getFive(){
  // we're RETURNING the promise, remember, a promise is a wrapper over our value
  return delay(100).then(function(){ // when the promise is ready
      return 5; // return the value 5, promises are all about return values
  })
}
// we _have_ to wrap it like this in the call site, we can't access the plain value
getFive().then(function(five){ 
   document.body.innerHTML = five;
});

Temelde, eşzamanlılık modeli nedeniyle yapamayacağımız bir değeri yerine - yapabileceğimiz bir değer için sarmalayıcı döndürüyoruz. > paketini aç , then ile then ile açabileceğiniz bir kutu gibi.

Bunu uygulama

Bu, orijinal API çağrınız için aynıdır, şunları yapabilirsiniz:

 
function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // process it inside the `then`
    });
}

foo().then(function(response){
    // access the value inside the `then`
})

Yani bu da aynı şekilde çalışıyor. Zaten eşzamansız çağrılardan değer döndüremediğimizi öğrendik, ancak sözleri kullanabilir ve bunları işleme koymak için zincirleyebiliriz. Şimdi yanıtın nasıl zamanuyumsuz bir aramadan döndürüleceğini biliyoruz.

ES2015 (ES6)

ES6, jeneratörleri tanıtıyor Orta ve sonra res dönebilen fonksiyonlaroldukları noktaya değiniyorlar. Bu genellikle diziler için kullanışlıdır, örneğin:

 
function* foo(){ // notice the star, this is ES6 so new browsers/node/io only
    yield 1;
    yield 2;
    while(true) yield 3;
}

Yinelenebilecek 1,2,3,3,3,3,.... dizisi üzerinde yineleyici döndüren bir işlevdir. Bu, kendi başına ilginç olmasına rağmen, bir çok olasılık için odayı açıyor, belli bir ilginç vaka var.

Ürettiğimiz dizi, sayılardan ziyade bir eylemler dizisiyse, bir işlem gerçekleştiğinde işlevi duraklatabilir ve işlevi sürdürmeden önce bekleyebiliriz. Dolayısıyla, bir sayı dizisi yerine, gelecek değerler dizisine ihtiyacımız var - yani: sözler

Bu biraz zor ama çok güçlü bir hile, senkronize olmayan bir şekilde asenkron kod yazmamızı sağlar. Bunu sizin için yapan birkaç "koşucu" var, birini yazmak kısa bir kod satırı ama bu cevabın kapsamı dışında. Bluebird'in Promise.coroutine modelini burada kullanıyorum, ancak co veya Q.async gibi başka paketleyiciler de var.

 
var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // notice the yield
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
});

Bu yöntem, diğer coroutinlerden alabileceğimiz bir söz verir. Örneğin:

 
var main = coroutine(function*(){
   var bar = yield foo(); // wait our earlier coroutine, it returns a promise
   // server call done here, code below executes when done
   var baz = yield fetch("/api/users/"+bar.userid); // depends on foo's result
   console.log(baz); // runs after both requests done
});
main();

ES2016 (ES7)

ES7’de, bu daha da standardize edilmiştir, şu anda birkaç teklif var, ancak hepsinde await vaat edebilirsiniz. Bu, yukarıdaki ES6 teklifi için async ve await anahtar kelimelerini ekleyerek sadece "şeker" (daha iyi sözdizimi) 'dir. Yukarıdaki örneği yaparak:

 
async function foo(){
    var data = await fetch("/echo/json"); // notice the await
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
}

Yine de aynı sözü veriyor :)

    
296
2017-05-23 12: 34: 51Z

Ajax'ı yanlış kullanıyorsunuz. Buradaki fikir, herhangi bir şey döndürmesini sağlamak değil, verileri verileri işleyen bir geri çağırma işlevi adı verilen bir öğeye dağıtmaktır.

Bu:

 
function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Gönderim işleyicisinde bir şey döndürmek hiçbir şey yapmaz. Bunun yerine verileri vermelisiniz ya da istediğinizi doğrudan başarı fonksiyonunun içinde yapmalısınız.

    
234
2015-11-21 14: 07: 03Z
  1. Bu cevap tamamen anlamlıdır ... başarı yönteminiz bir geri çağırma içinde yalnızca bir geri çağırmadır. Sadece success: handleData'a sahip olabilirsiniz ve işe yarayabilirdi.
    2016-01-04 15: 49: 49Z
  2. "Peki" handleData "ifadesini" handleData "dışında döndürmek istersen ... nasıl yapardın ...? ... çünkü basit bir geri dönüş, onu ajax'ın "başarı" geri çağrısına döndürür ... ve "handleData" dışında ... ...
    2016-02-19 16: 02: 18Z
  3. @ Jacques & @pesho hristov Bu noktayı kaçırdınız. Gönderme işleyicisi success yöntemi değil, $.ajax'un çevresi kapsamıdır.
    2018-05-28 12: 37: 13Z
  4. @ travnik Bunu özlemedim. HandleData içeriğini aldıysanız ve başarı yöntemine koyduysanız, tam olarak aynı şekilde hareket ederdi ...
    2018-06-13 01: 21: 43Z

En basit çözüm, bir JavaScript işlevi oluşturmaktır ve Ajax success geri çağırma için çağırır.

 
function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 
    
222
2017-01-15 06: 17: 51Z
  1. Kimin olumsuz oy kullandığını bilmiyorum. Fakat bu, üzerinde çalıştığım bir çalışma, bu yaklaşımı bütün bir uygulama oluşturmak için kullandım. Jquery.ajax veriyi döndürmez, bu yüzden yukarıdaki yaklaşımı kullanmak daha iyidir. Eğer yanlışsa, lütfen bunu yapmanın daha iyi bir yolunu açıklayın ve önerin.
    2014-03-28 18: 12: 35Z
  2. Üzgünüm, yorum yapmayı unuttum (Genellikle yaparım!). Oy verdim. Düşüşler, olgusal doğruluğu ya da eksikliğini göstermez, bağlamında ya da yokluğunda faydalı olduğunu gösterir. Cevabınızı yararlı bulmuyorum, bu çoktan daha detaylı olarak açıklayan Felix'in verdiği. Bir taraftanot, neden JSON ise bu cevabı neden paylaştırdınız?
    2014-04-10 09: 18: 07Z
  3. tamam .. @Benjamin bir JSON Nesnesini dizeye dönüştürmek için stringify kullandım. Ve amacını açıkladığın için teşekkürler. Daha ayrıntılı cevaplar yayınlamayı aklınızda tutacaktır.
    2014-04-10 10: 27: 10Z
  4. Peki ya "responseObj" ifadesini "successCallback" dışında döndürmek istiyorsanız ... nasıl yapacaksınız? ... çünkü basit bir geri dönüş, onu, ajax'ın "başarı" geri çağrısına döndürür ... ve "successCallback" dışında değildir ...
    2016-02-19 16: 02: 57Z

Korkunç görünümlü, elle çizilmiş bir çizgi romanla cevap vereceğim. İkinci resim, kod örneğinizde result'un undefined olmasının nedenidir.

resim tanımını buraya girin

    
203
2016-08-11 17: 12: 24Z
  1. Bir resim bin kelimeye bedeldir , A Kişisi - Arabasını düzeltmek için B kişisinden B detaylarını isteyin, dönüş B Kişisi - Ajax Araması yapar ve yanıt alındığında Ajax Success işlevi B Kişi işlevini çağırır ve yanıtı bağımsız değişken olarak iletir, A Kişisi alır. Cevap.
    2016-10-31 17: 48: 09Z
  2. Kavramları açıklamak için her resimle kod satırları eklerseniz çok iyi olurdu.
    2018-02-05 00: 32: 58Z

Angular1

AngularJS kullananlar için bu durumu Promises kullanarak halledebilirsiniz.

İşte yazıyor,

  

Sözler, eşzamansız asenkron işlevlerde kullanılabilir ve birinin birden çok işlevi birlikte zincirlemesine olanak tanır.

Güzel bir açıklama bulabilirsiniz burada .

Aşağıda belirtilen dokümanlar 'da bulunan örnek.

 
  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 ve Sonra

Angular2’da aşağıdaki örneğe bakın, ancak önerilir Observables’u Angular2’la kullanmak.

 
 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

Bunu bu şekilde tüketebilirsiniz,

 
search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

Buradaki orijinal yayınına bakın. Ancak Typescript, native es6 Sözlerini desteklemiyor, kullanmak istiyorsanız, eklentiye ihtiyacınız olabilir bunun için.

Ek olarak burada spec burada tanımlanacak vaatler verilmiştir.

    
147
2017-07-06 04: 45: 28Z
  1. Bu, sözlerin bu sorunu nasıl çözebileceğini açıklamıyor.
    2014-11-04 02: 29: 10Z
  2. Çalışmıyor. promiseB 'tanımsız' olacak
    2014-11-21 15: 35: 47Z
  3. jQuery ve fetch yöntemlerinin her ikisi de iade sözleri veriyor yanı sıra. Cevabınızı gözden geçirmenizi öneririm. Her ne kadar jQuery's tam olarak değilaynı (o zaman orada, ancak yakalama yok).
    2015-02-19 19: 24: 49Z

Buradaki yanıtların çoğu, tek bir eşzamansız işleminiz olduğunda faydalı önerilerde bulunur, ancak bazen bu, bir dizideki veya her listedeki her biri için eşzamansız işlem yapmanız gerektiğinde ortaya çıkar benzeri yapı. Baştan çıkarma, bunu yapmaktır:

 
// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Örnek:

 
// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

İşe yaramayan sebep,

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
'dan gelen geri aramaların, sonuçları kullanmaya çalıştığınız zaman henüz başlamamasıdır.

Öyleyse, bir diziniz varsa (veya bir tür listeniz varsa) ve her giriş için eşzamansız işlemler yapmak istiyorsanız, iki seçeneğiniz vardır: İşlemleri paralel olarak (üst üste binen) veya seri olarak (birbiri ardına sırayla yapın) ).

Paralel

Hepsini başlatabilir ve kaç tane geri arama beklediğinizi takip edebilir ve ardından bu kadar geri arama aldığınızda sonuçları kullanabilirsiniz:

 
.as-console-wrapper {
  max-height: 100% !important;
}

Örnek:

 doSomethingAsync  
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

(

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}
ile başarabilir ve sadece
var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
kullanabiliriz, ancak bu çağrılar olağanüstü olduğunda
.as-console-wrapper {
  max-height: 100% !important;
}
'un değiştirilme olasılığını açığa çıkarır ...)

expecting’dan results.length === theArray.length’dan theArray’a kadar olan sonuçları, sonuçların sıra dışı kalsa bile (async çağrıları zorunlu olarak tamamlanmadığı için) Onlar başlatıldı).

Fakat bu sonuçları bir işlevden döndürmeniz gerekirse ? Diğer cevapların işaret ettiği gibi; işlevinizi geri çağırmayı kabul edip aramanız gerekir (veya Promise ). İşte bir geri arama sürümü:

 index

Örnek:

 forEach  results

Veya işte bunun yerine

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});
döndüren bir sürüm:  
function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Elbette, eğer

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
bize hatalar geçerse, bir hata olduğunda söz vermeyi reddetmek için
.as-console-wrapper {
  max-height: 100% !important;
}
'u kullanırız.)

Örnek:

 Promise  
function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

(Alternatif olarak, söz veren doSomethingAsync için bir sarmalayıcı yapabilir ve ardından aşağıdakileri yapabilirsiniz ...)

reject size bir Promise verirse ,

: 'ı kullanabilirsiniz. /p>  

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}

.as-console-wrapper {
  max-height: 100% !important;
}
’un ikinci ve üçüncü bir argümanı görmezden geleceğini biliyorsanız, doğrudan doSomethingAsync’a geçebilirsiniz (doSomethingAsync geri aramasını üç argümanla çağırır, ancak çoğu kişi yalnızca ilkini kullanır):  Promise.all

Örnek:

 
function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry);
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});
 doSomethingAsync

map’un sözünü, hepsi çözümlendiğinde verdiğiniz sözlerin sonuçlarının bir dizi dizisi ile çözdüğünü veya verdiğiniz sözlerin ilk reddettiği zaman sözünü reddettiğini unutmayın. .

Seri

İşlemlerin paralel olmasını istemediğinizi varsayalım. Birbiri ardına çalıştırmak istiyorsanız, bir sonraki işleme başlamadan önce her bir işlemin tamamlanmasını beklemeniz gerekir. İşte bunu yapan ve sonucuyla geri arama yapan bir fonksiyonun örneği:

 map

(Çalışmayı seri olarak yaptığımızdan, sıra dışı sonuç alamayacağımızı bildiğimiz için

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});
'u kullanabiliriz. Yukarıdakilerde
function doSomethingWith(theArray) {
    return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}
'u kullanabilirdik, ancak bazılarında Kullanacağımız bir endekste sahip olmadığımız örnekler.)

Örnek:

 
function doSomethingWith(theArray) {
    return Promise.all(theArray.map(doSomethingAsync));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
 
.as-console-wrapper {
  max-height: 100% !important;
}

(Veya yine, Promise.all için size bir söz veren ve aşağıdakileri yapan bir sarıcı oluşturun ...)

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});
size bir Söz verirse, ES2017 + sözdizimini kullanabilirseniz (belki de Babel ), bir results.push(result) işlevi , results[index] = result; ve
function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}
:  
function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}

Örnek:

 
.as-console-wrapper {
  max-height: 100% !important;
}
 doSomethingAsync

ES2017 + sözdizimini kullanamıyorsanız (henüz), " Promise azaltma "deseni (bu, normal Promise azaltma işleminden daha karmaşıktır çünkü sonucu birden diğerine aktarmıyoruz, bunun yerine sonuçlarını bir dizide toplamaktayız):

 doSomethingAsync

Örnek:

 async  for-of

... ES2015 + ok ile daha az hantal olan fonksiyonlar :

 await

Örnek:

 
async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});
 
async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}
    
131
2019-04-26 07: 50: 55Z
  1. Kodun
    async function doSomethingWith(theArray) {
        const results = [];
        for (const entry of theArray) {
            results.push(await doSomethingAsync(entry));
        }
        return results;
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", results);
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    bölümünün nasıl çalıştığını açıklayabilir misiniz? Çözümünüzün geri arama sürümü benim için çok iyi çalışıyor, sadece bu ifadeyle tamamlanan yanıt sayısını nasıl kontrol ettiğinizi anlamıyorum. Benim açımdan sadece bilgi eksikliği olduğunu takdir edin. Çek yazmanın alternatif bir yolu var mı?
    2017-05-28 10: 21: 35Z
  2. @ Sarah:
    .as-console-wrapper {
      max-height: 100% !important;
    }
    ,
    function doSomethingWith(theArray) {
        return theArray.reduce(function(p, entry) {
            return p.then(function(results) {
                return doSomethingAsync(entry).then(function(result) {
                    results.push(result);
                    return results;
                });
            });
        }, Promise.resolve([]));
    }
    doSomethingWith(theArray).then(function(results) {
        console.log("Results:", results);
    });
    
    değeriyle başlar; bu, ne kadar istek yapacağımızdır. Bu isteklerin tümü başlatılıncaya kadar geri çağrının aranmayacağını biliyoruz. Geri aramada
    function doSomethingWith(theArray) {
        return theArray.reduce(function(p, entry) {
            return p.then(function(results) {
                return doSomethingAsync(entry).then(function(result) {
                    results.push(result);
                    return results;
                });
            });
        }, Promise.resolve([]));
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", results);
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    .as-console-wrapper {
      max-height: 100% !important;
    }
    bunu yapar: 1. Düşüşler
    function doSomethingWith(theArray) {
        return theArray.reduce(function(p, entry) {
            return p.then(function(results) {
                return doSomethingAsync(entry).then(function(result) {
                    results.push(result);
                    return results;
                });
            });
        }, Promise.resolve([]));
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", results);
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    (bir yanıt aldık, bu yüzden daha az yanıt bekliyoruz) ve değerinden sonra değerinin düşmesi 0 ise (biz değiliz) daha fazla yanıt beklemek)), bitti!
    2017-05-28 18: 31: 11Z
  3. @ PatrickRoberts - Teşekkürler !! Evet, kopyala ve yapıştır hatası, bu örnekte ikinci argüman tamamen göz ardı edildi (bu, başarısız olmasının tek nedeni, belirttiğiniz gibi,
    .as-console-wrapper {
      max-height: 100% !important;
    }
    'un olmamasıydı). :-) Düzeltildi.
    2019-04-26 07: 51: 43Z

Bu örneğe bir göz atın:

 
function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Gördüğünüz gibi

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}
’un geri dönen bir olduğu, çözülmüş bir sözün olduğu (
function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
’un geri döndüğü tarih). Böylece, $http.get isteği tamamlanıncaya ve ardından console.log (res.joke) yürütülene kadar bekleyin (normal bir asenkron akış olarak).

Bu plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/p>

ES6 yolu (zaman uyumsuz - bekliyor)

 
.as-console-wrapper {
  max-height: 100% !important;
}
    
102
2018-11-23 12: 19: 11Z

Eşzamansız bir işlevden değer döndürmek için başka bir yaklaşım, eşzamansız işlevden sonucu depolayacak bir nesneyi iletmektir.

İşte aynı bir örnek:

 if (--expecting === 0)

Zaman uyumsuz işlem sırasında değeri depolamak için expecting nesnesini kullanıyorum. Bu, sonucun zamanuyumsuz işten sonra bile kullanılabilir olmasını sağlar.

Bu yaklaşımı çok kullanırım. Bu yaklaşımın ne kadar iyi sonuç verdiğini bilmek ilgimi çekecektir.h ardışık modüller katılır.

    
88
2016-12-17 12: 55: 25Z
  1. Burada bir nesneyi kullanma konusunda özel bir şey yok. Direkt olarak array.length'a cevap vermen iyi olurdu. İşe yarıyor çünkü değişkenini okuyorsanız async işlevi tamamlandı.
    2015-09-02 13: 18: 11Z

Bu, birçok yeni JavaScript çerçevesinde kullanılan veri bağlama iki yolunun yer aldığı yerlerden biridir ...

Öyleyse Açısal, Tepki veya veri bağlama iki yönlü veya mağaza konsepti yapan başka bir çerçeve kullanıyorsanız, bu sorun çözüldü sizin için, yani kolay bir deyişle, sonucunuz ilk aşamada if (--expecting === 0)'dur, bu nedenle verileri almadan önce expecting'unuz olur, ardından sonucu alır almaz, güncellenir ve hangi cevabı yeni değere atarsınız. Ajax aramanızdan ...

Ancak, örneğin bu soruda istediğiniz gibi saf javascript veya jQuery ile nasıl yapabilirsiniz?

Örneğin, sizin için işlemek için geri arama , söz ve son zamanlarda gözlenebilir kullanabilirsiniz, örneğin başarı gibi bir işleve sahip olduğumuz sözlerinde () veya sonra () verileriniz sizin için hazır olduğunda, geri arama ile aynı olduğunda veya gözlenebilir 'de abone ol işleviyle aynı şekilde çalıştırılır.

Örneğin, jQuery kullandığınız durumda, bunun gibi bir şey yapabilirsiniz:

 results

Bu zaman uyumsuzluğu gerçekleştirmenin yeni yolları olan vaatler ve gözlemlenebilirler hakkında daha fazla bilgi çalışması için.

    
88
2019-05-21 14: 22: 58Z
  1. Bu, global kapsamda iyidir, ancak bazı modül bağlamlarında, geri arama için örn.
    var app = angular.module('plunker', []);
    
    app.controller('MainCtrl', function($scope,$http) {
    
        var getJoke = function(){
            return $http.get('http://api.icndb.com/jokes/random').then(function(res){
                return res.data.value;  
            });
        }
    
        getJoke().then(function(res) {
            console.log(res.joke);
        });
    });
    
    2017-07-24 06: 14: 12Z
  2. React tek yönlü veri bağlama olduğundan bu aslında yanlıştır
    2018-05-04 15: 57: 05Z
  3. @ MatthewBrent, hatalı değilsiniz ancak haklı değilsiniz de, Tepki destekleri nesnedir ve değiştirilirse uygulama boyunca değişir, ancak geliştiricinin önerdiği şekilde değil kullanmak için ...
    2018-05-14 07: 34: 28Z

Sözler ve geri aramalar birçok durumda iyi sonuç verirken, arkada şöyle bir şey ifade etmek acı vericidir:

 getJoke

res.data.value’dan sonra sona erecektiniz;

(function(){
  async function getJoke(){
    let response = await fetch('http://api.icndb.com/jokes/random');
    let data = await response.json();
    return data.value;
  }

  getJoke().then((joke) => {
    console.log(joke);
  });
})();
undefined olup olmadığını kontrol edin ve geri aramayı buna göre arayın.  
var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

tamam küçük örneklerde, benzer birçok durum ve hata işlemeniz olduğunda sinir bozucu olur.

result, sorunu çözmede yardımcı olur.

 result

buradaki projeyi kontrol edebilirsiniz.

    
80
2016-05-09 13: 02: 40Z
  1. @ recurf - Bu benim projem değil. Sorun izleyicilerini kullanmayı deneyebilirsiniz.
    2017-01-20 15: 22: 44Z
  2. 2017-06-07 03: 19: 47Z
  3. Bu hala geçerli mi?
    2018-03-18 19: 43: 54Z
  4. Düğümün en yeni sürümlerinden bazılarını kullanıyorsanız undefined'dan yararlanabilirsiniz. Birisi daha eski sürümlerle takılmışsa bu yöntemi kullanabilir.
    2018-03-20 08: 18: 27Z

Kısa cevap, bunun gibi bir geri arama yapmanız gerekiyor:

 result = undefined     
76
2016-08-09 18: 32: 41Z

Yazdığım aşağıdaki örnek, nasıl yapılacağını gösterir

  • Asenkron HTTP çağrılarını yönetme;
  • Her bir API çağrısından yanıt bekleyin;
  • Söz Ver modelini kullanın;
  • Promise.all adresini kullanın Birden fazla HTTP çağrısına katılacak model;

Bu çalışma örneği bağımsız. Arama yapmak için

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});
nesnesini kullanan basit bir istek nesnesini tanımlayacaktır. Bir sürü sözün tamamlanmasını bekleyecek basit bir işlev tanımlayacaktır.

Bağlam. Örnek, $.ajax({url: "api/data", success: fooDone.bind(this)}); nesneyi aramak için Spotify Web API uç noktasını sorguluyor Belirli bir sorgu dizesi kümesi için:

 
if (!name) {
  name = async1();
}
async2(name);

Her öğe için yeni bir Söz, bir blok - async1'u ateşler, sonucu ayrıştırır, sonuç dizisini temel alan yeni bir sözler dizisi hazırlar; bu, name'daki Spotify

async1(name, callback) {
  if (name)
    callback(name)
  else {
    doSomething(callback)
  }
}

async1(name, async2)
nesnelerinin bir listesidir ve yeni HTTP çağrısını Fibers'da yürütür. Zaman uyumsuz.

Daha sonra, birden çok ve tamamen eşzamansız iç içe HTTP çağrıları oluşturmanıza olanak sağlayan iç içe geçmiş bir Promise yapısını görebilir ve

var Fiber = require('fibers')

function async1(container) {
  var current = Fiber.current
  var result
  doSomething(function(name) {
    result = name
    fiber.run()
  })
  Fiber.yield()
  return result
}

Fiber(function() {
  var name
  if (!name) {
    name = async1()
  }
  async2(name)
  // Make any number of async calls from here
}
ile her çağrı alt kümesinin sonuçlarını birleştirebilirsiniz.

NOT Son Spotify async-await API'leri, istek başlıklarında belirtilmesi için bir erişim belirteci gerektirecektir:

 
function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});

Dolayısıyla, aşağıdaki örneği çalıştırmanız, erişim kartınızı istek başlıklarına koymanız gerekir:

 XMLHttpRequest

Bu çözümü çok tartıştım burada .

    
74
2018-11-28 16: 42: 31Z

2017 cevabı: şimdi her mevcut tarayıcıda ve düğümde tam olarak ne istersen yapabilirsin

Bu oldukça basit:

  • Bir Söz Verin
  • 'bekliyor' , JavaScript'in bir değere (HTTP yanıtı gibi) çözülecek sözünü beklemesini söyler
  • 'async' anahtar kelimesini ekleyin üst işlevine

İşte kodunuzun çalışan bir sürümü:

 playlist

bekliyor, tüm mevcut tarayıcılarda ve düğüm 8’de desteklenir

    
71
2018-10-01 10: 06: 17Z
  1. Maalesef, bu yalnızca vaat veren işlevlerle çalışır - örneğin geri arama kullanan Node.js API ile çalışmaz. Ve Babel olmadan kullanmanızı tavsiye etmem, çünkü herkes "geçerli tarayıcılar" kullanmıyor.
    2017-06-08 06: 47: 10Z
  2. @ MichałPerłakowski düğümü 8, nodejs içeriyor. node.js API'nin iade vaadi için kullanılabilecek org /api /util.html # util_util_promisify_original . Suya vaktiniz ve paranız olup olmadığıgüncel olmayan tarayıcıları açıkça belirtin ki durumunuza bağlı.
    2017-06-09 18: 28: 16Z
  3. IE 11 hala 2018’de güncel bir tarayıcıdır, ne yazık ki ve
    [
     "search?type=playlist&q=%22doom%20metal%22",
     "search?type=playlist&q=Adele"
    ]
    
    ’u desteklememektedir
    2018-10-04 14: 51: 34Z
  4. IE11 geçerli bir tarayıcı değil. 5 yıl önce piyasaya sürüldü, kanuna göre% 2,5'lik bir dünya pazar payına sahip ve birileri mevcut tüm teknolojileri görmezden gelmek için bütçenizi iki katına çıkarmazsa, çoğu insanın zamanına değmez.
    2018-10-04 14: 57: 29Z

Uzaktan arama yapmak için bu özel kütüphaneyi (Promise kullanılarak yazılmış) kullanabilirsiniz.

 ExecutionBlock

Basit kullanım örneği:

 user     
63
2016-12-17 10: 59: 13Z
  

Js tek dişlidir.

Tarayıcı üç bölüme ayrılabilir:

1) Etkinlik Döngüsü

2) Web API

3) Etkinlik Sırası

Olay Döngüsü sonsuza dek çalışır, yani bir tür sonsuz döngü. Anvent Kuyruğu, tüm işlevlerinizin bir olaya itildiği yerdir (örnek: klik) bu, tek tek sıradan yürütülür ve bu işlevi yürüten Olay döngüsüne konur ve ilk çalıştırıldıktan sonra bir sonrakine kendini hazırlar. Bu, bir işlevin yürütülmesi, sıradaki işlevin olay döngüsünde yürütülene kadar başlamayacağı anlamına gelir.

Şimdi sıradaki iki işlevi ittiğimizi düşünelim, biri sunucudan veri almak ve diğeri bu verileri kullanır. Sırada serverRequest () işlevini önce sıraya, sonra useiseData () işlevini ilerledik. serverRequest işlevi olay döngüsüne gider ve sunucudan veri almanın ne kadar zaman alacağını asla bilmediğimizden sunucuya çağrı yapar bu yüzden bu sürecin zaman alması beklenir ve böylece etkinlik döngümüzle meşgul oluruz, böylece sayfamızı asarız, Web API'sinin rol aldığı yer bu işlevi olay döngüsünden alır ve sunucuyu olay döngüsünü serbest bırakarak gerçekleştirir, böylece bir sonraki işlevi yürütebiliriz Kuyruktaki bir sonraki fonksiyon, döngü içine giren fakat kullanılabilecek veri olmadığı için israf olur ve bir sonraki işlevin yürütülmesi sıranın sonuna kadar devam eder. (Buna Async denir, yani biz başka bir şey yapabiliriz). veri al)

serverRequest () işlevimizin bir kodda bir dönüş ifadesi olduğunu varsayalım, sunucudan gelen verileri geri aldığımızda Web API'si kuyruk sonunda kuyruğa sokar. Sıranın sonunda ilerledikçe, bu verileri kullanmak için kuyruğumuzda kalan bir işlev kalmadığından verilerini kullanamayız. Dolayısıyla, Async Çağrısından bir şey döndürmek mümkün değildir.

Dolayısıyla, bunun çözümü geri arama veya söz veremem .

Buradaki yanıtlardan bir görüntü, Geri arama kullanımını doğru şekilde açıklıyor ... İşlev çağrısı (sunucudan döndürülen verileri kullanan işlev) işlev çağrısı sunucusuna veriyoruz.

 CallBack

 ExecutionProfileBlock

Kodumda buna

denir.  Promise.all

Zaman uyumsuz arama yapmak için ECMA’daki (2016/17) yeni yöntemler için burayı okuyun (@Felix Kling Cevap) https://stackoverflow.com/a/14220323/7579856

    
58
2018-03-16 16: 48: 55Z

Başka bir çözüm, kodu sıralı uygulayıcı nsynjs ile yürütmektir.

Temel fonksiyon söz veriliyorsa

nsynjs tüm sözleri sırayla değerlendirecek ve söz sonucunu search özelliğine ekleyecektir:

 
-H "Authorization: Bearer {your access token}" 

Temel fonksiyon söz verilmezse

1. Adım: Geri çağırma işlevini nsynjs-farkında sarmalayıcıya sarın (söz verilmiş sürümü varsa, bu adımı atlayabilirsiniz):

 
var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "<br/>"
    }
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
    call: function(what, response) {
        var request;
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Internet Explorer
            try {
                request = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                  request = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {}
            }
        }

        // State changes
        request.onreadystatechange = function() {
            if (request.readyState === 4) { // Done
                if (request.status === 200) { // Complete
                    response(request.responseText)
                }
                else
                    response();
            }
        }
        request.open('GET', what, true);
        request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
        request.send(null);
    }
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
    var self = this;
    var promises = [],
                   index = 0;
    items.forEach(function(item) {
        promises.push(function(item, i) {
            return new Promise(function(resolve, reject) {
                if (block) {
                    block.apply(this, [item, index, resolve, reject]);
                }
            });
        }(item, ++index))
    });
    Promise.all(promises).then(function AcceptHandler(results) {
        if (done) done(results);
    }, function ErrorHandler(error) {
        if (fail) fail(error);
    });
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
    var url = "https://api.spotify.com/v1/"
    url += item;
    console.log( url )
    SimpleRequest.call(url, function(result) {
        if (result) {

            var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
                return item.owner.href;
            })
            resolve(profileUrls);
        }
        else {
            reject(new Error("call error"));
        }
    })
}

arr = [
    "search?type=playlist&q=%22doom%20metal%22",
    "search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
    console.log("Making request [" + index + "]")
    ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

    console.log("All profiles received " + results.length);
    //console.log(JSON.stringify(results[0], null, 2));

    ///// promiseall again

    var ExecutionProfileBlock = function(item, index, resolve, reject) {
        SimpleRequest.call(item, function(result) {
            if (result) {
                var obj = JSON.parse(result);
                resolve({
                    name: obj.display_name,
                    followers: obj.followers.total,
                    url: obj.href
                });
            } //result
        })
    } //ExecutionProfileBlock

    promiseAll(results[0], function(item, index, resolve, reject) {
        //console.log("Making request [" + index + "] " + item)
        ExecutionProfileBlock(item, index, resolve, reject);
    }, function(results) { // aggregated results
        console.log("All response received " + results.length);
        console.log(JSON.stringify(results, null, 2));
    }

    , function(error) { // Error
        console.log(error);
    })

    /////

  },
  function(error) { // Error
      console.log(error);
  });
<div id="console" />

2. Adım. Senkronize mantığı fonksiyona yerleştirin:

 
(async function(){

var response = await superagent.get('...')
console.log(response)

})()

Adım 3. Eşzamanlı olarak ma işlevini çalıştırınnsynjs yoluyla nner:

 await/async

Nsynjs, tüm işleçleri ve ifadeleri adım adım değerlendirecek ve bazı yavaş fonksiyonların sonuçlarının hazır olmaması durumunda yürütmeyi duraklatacak.

Burada daha fazla örnek: https://github.com/amaksr/nsynjs/tree/ana /örnekler

    
57
2019-04-03 16: 00: 18Z
  1. Bu ilginç. Eşzamansız çağrıların diğer dillerde yaptığınız gibi çağrılmasına nasıl izin verdiğini seviyorum. Ancak teknik olarak gerçek JavaScript değil mi?
    2017-06-16 23: 55: 06Z

JavaScript’in gizemleri ile mücadele ederken karşılaştığımız çok yaygın bir konudur. Bugün bu gizemi açığa çıkarmaya çalışmama izin verin.

Basit bir JavaScript işlevi ile başlayalım:

 
function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

Bu basit bir senkronize fonksiyon çağrısıdır (her kod satırının bir sonraki sırada olandan önce 'işi ile bittiği') ve sonuç beklendiği gibi olur.

Şimdi, fonksiyonumuza küçük bir gecikme getirerek biraz kod ekleyelim, böylece tüm kod satırları sırayla 'bitmedi'. Böylece, asenkron işlevin davranışını taklit eder:

 
$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

Öyleyse işte orada, bu gecikme beklediğimiz işlevselliği bozdu! Ama tam olarak ne oldu? Eh, koda bakarsanız oldukça mantıklı. işlev

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}
, yürütme üzerine hiçbir şey döndürmez (bu nedenle döndürülen değer
function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}
'dur), ancak 'wohoo' işlevini döndürmek için 1 saniye sonra bir işlevi yürüten bir zamanlayıcı başlatır. Ancak gördüğünüz gibi, çubuğa atanan değer, daha sonra gelen başka bir şey değil, foo () öğesinden derhal geri gönderilen şeylerdir.

Peki, bu sorunu nasıl ele alıyoruz?

İşlevimizden bir PROMISE isteyelim. Söz vermek gerçekten ne anlama geldiğidir: bu, işlevin gelecekte elde edeceği herhangi bir çıktıyı sağlamanızı garanti ettiği anlamına gelir. öyleyse, yukarıdaki küçük sorunumuz için eylemde görelim:

 data

Böylece, özet - ajax tabanlı çağrılar vb. gibi asenkron işlevlerin üstesinden gelmek için,

function synchronousCode() {

    var getURL = function(url) {
        return window.fetch(url).data.text().data;
    };
    
    var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
    console.log('received bytes:',getURL(url).length);
    
};

nsynjs.run(synchronousCode,{},function(){
    console.log('synchronousCode done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
değerine (geri dönmek istediğiniz) söz verebilirsiniz. Bu nedenle, kısaca, eşzamansız işlevlerde, geri dönme yerine değeri çözersiniz .

GÜNCELLEME (Async /await ile vaat ediyor)

Sözler ile çalışmak için

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;
'u kullanmanın yanı sıra, bir yaklaşım daha var. Buradaki fikir, bir sonraki kod satırına geçmeden önce zaman uyumsuz bir işlevi tanımak ve ardından vaatleri beklemek 'i beklemektir. Hala kaputun altındaki sadece
function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}
, ama farklı bir sözdizimsel yaklaşımla. İşleri netleştirmek için, aşağıda bir karşılaştırma bulabilirsiniz:

ardından /catch sürümü:

 
nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

zaman uyumsuz /beklemede sürüm:

 
function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here
    
43
2018-10-09 17: 33: 32Z
  1. , bu hala bir söz veya async /await'ten bir değer döndürmenin en iyi yolu olarak mı kabul ediliyor?
    2018-09-26 20: 58: 21Z
  2. @ edwardsmarkf Şahsen böyle iyi bir yol olduğunu sanmıyorum. Daha sonra /catch, zaman uyumsuz /beklemenin yanı sıra kodumun zaman uyumsuz kısımları için üreteçlerle ilgili sözler kullanıyorum. Büyük ölçüde kullanımın içeriğine bağlıdır.
    2018-10-03 16: 12: 28Z

ECMAScript 6, asenkron bir tarzda kolayca programlamanıza izin veren 'jeneratörlere' sahiptir.

 
function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

Yukarıdaki kodu çalıştırmak için şunu yapın:

 foo()

ES6'yı desteklemeyen tarayıcıları hedeflemeniz gerekirse, ECMAScript 5'i oluşturmak için kodu Babel veya closure-compiler yoluyla çalıştırabilirsiniz.

Geri arama undefined, bir diziye sarılır ve bunları okuduğunuzda imha edilir; böylece desen, birden çok argüman içeren geri aramalarla başa çıkabilir. Örneğin, node fs ile:

 
function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when execution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});
    
37
2018-07-31 10: 35: 51Z
  1. Bunun neden aşağı oy kullandığını bilmek isterim. Daha önce verilmemiş iyi bir basit cevap gibi görünüyor.
    2018-02-17 17: 49: 50Z

Asenkron isteklerle çalışmak için bazı yaklaşımlar:

  1. Tarayıcı Promise nesnesi
  2. Q - JavaScript için bir söz kütüphanesi
  3. A + Promises.js
  4. ertelenen jQuery
  5. XMLHttpRequest API
  6. Geri arama konseptini kullanma - İlk yanıtta uygulama olarak

Örnek: jQuery, birden çok istekle çalışmak üzere ertelenen uygulama

 resolve
    
36
2017-06-22 09: 31: 40Z

Kısa cevap : then/catch yönteminiz derhal geri döner, promises çağrısı işlev döndükten sonra zaman uyumsuz olarak yürütülür . Sorun o zaman, bir kez daha zaman zaman uyumsuz çağrı tarafından alınan sonuçların nasıl depolanacağıdır.

Bu konuya birkaç çözüm önerildi. Belki de en kolay yol, bir nesneyi

function fetchUsers(){
   let users = [];
   getUsers()
   .then(_users => users = _users)
   .catch(err =>{
      throw err
   })
   return users;
 }
yöntemine iletmek ve eşzamansız çağrı tamamlandıktan sonra sonuçları bu nesnenin bir üyesinde saklamaktır.  
  async function fetchUsers(){
     try{
        let users = await getUsers()
        return users;
     }
     catch(err){
        throw err;
     }
  }

function* myGenerator() {
    const callback = yield;
    let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
    console.log("response is:", response);

    // examples of other things you can do
    yield setTimeout(callback, 1000);
    console.log("it delayed for 1000ms");
    while (response.statusText === "error") {
        [response] = yield* anotherGenerator();
    }
}
numaralı aramanın yine de hiçbir işe yaramayacağını unutmayın. Ancak, zaman uyumsuz arama sonucu
const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function
'da depolanacak.     
33
2015-09-23 22: 52: 03Z
  1. Bu işe yarıyorken, genel bir değişkene atanmaktan daha iyi değil.
    2015-09-23 22: 53: 07Z

...args başarısında

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);
işlevini kullanın. Bu şekilde dene. Basit ve anlaşılması kolaydır.  
var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();
    
33
2017-11-17 09: 15: 45Z

Kendimizi "zaman" olarak adlandırdığımız bir boyutta ilerleyen görünen bir evrende buluruz. Zamanın gerçekte ne olduğunu anlamıyoruz, ancak bunun hakkında konuşmamıza ve konuşmamıza izin veren soyutlamalar ve kelimeler geliştirdik: "geçmiş", "şimdi", "gelecek", "önce", "sonra".

Oluşturduğumuz bilgisayar sistemleri - giderek daha fazla - önemli bir boyut olarak zaman alıyor. Gelecekte gerçekleşecek bazı şeyler var. Öyleyse sonunda ilk şeyler gerçekleştikten sonra başka şeylerin de olması gerekir. Bu "asenkroniklik" olarak adlandırılan temel kavramdır. Gittikçe ağlaşan dünyamızda, en yaygın eşzamansızlık vakası, bazı uzak sistemlerin bazı isteklere cevap vermesini beklemektedir.

Bir örnek ele alalım. Siz sütçüyü arayın ve biraz süt sipariş edin. Geldiğinde kahvene koymak istiyorsun. Şu anda sütü kahvenize koyamazsınız, çünkü henüz burada değil. Kahvene koymadan önce gelmesini beklemelisin. Başka bir deyişle, aşağıdaki işe yaramaz:

 foo()

JS'nin, $ajax()'u yürütmeden önce foo()'un tamamlanması için beklemesini beklemesi gerektiğini bilmesinin yolu yoktur. Başka bir deyişle,

function foo(result) {
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;   // Store the async result
        }
    });
}

var result = { response: null };   // Object to hold the async result
foo(result);                       // Returns before the async completes
'un asenkronize olduğunu bilmiyor - gelecek zamana kadar sütle sonuçlanmayacak bir şey. JS ve diğer bildirimsel diller, birbirini beklemeden birbiri ardına yürütür.

Klasik JS yaklaşımı bu sorunaJS'nin, aktarılabilecek birinci sınıf nesneler olarak işlevleri desteklediği gerçeği, bir işlevi, zaman zaman görevini tamamladığında daha sonra çağıracağı zaman asenkron isteğe parametre olarak geçirmektir. Bu "geri arama" yaklaşımıdır. Şuna benziyor:

 foo()

result.response başladı, sütü emretti, sonra, ne zaman ve yalnızca geldiğinde callback()'u çağırdı.

Bu geri çağırma yaklaşımındaki sorun, sonucunu foo() ile bildiren bir işlevin normal anlamını kirletmesidir; bunun yerine, işlevler parametre olarak verilen bir geri çağrıyı arayarak sonuçlarını bildirmemelidir. Ayrıca, bu yaklaşım daha uzun olay dizileriyle uğraşırken hızlı bir şekilde hantallaşabilir. Mesela, sütün kahveye konmasını beklemek istediğimi ve daha sonra sadece kahve içmek gibi üçüncü bir adım atmak istediğimi varsayalım. Sonunda böyle bir şey yazmaya ihtiyacım var:

 
var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();

hem içerisine koyulacak süt, hem de süt koyulduktan sonra uygulanacak eylem (

var milk = order_milk();
put_in_coffee(milk);
) için order_milk'a geçiyorum. Bu kodun yazılması, okunması ve hata ayıklanması zorlaşıyor. >

Bu durumda, sorudaki kodu şu şekilde yeniden yazabiliriz:

 put_in_coffee

Sözleri girin

Bu, bir türden geleceği veya asenkronize bir sonucu temsil eden belirli bir değer türü olan bir "söz" kavramının motivasyonuydu. Zaten olan veya gelecekte gerçekleşecek olan veya hiç gerçekleşmeyecek bir şeyi temsil edebilir. Sözlerin, order_milk adında, sözün temsil ettiği sonuç gerçekleştiğinde gerçekleştirilecek bir eylemi geçirdiğiniz tek bir yöntemi vardır.

Süt ve kahvelerimizde, gelen süt için bir söz vermek üzere

order_milk(put_in_coffee);
tasarlıyoruz, ardından order_milk'u put_in_coffee eylemi olarak belirtiyoruz:  return

Bunun bir avantajı, gelecekteki oluşumların sıralarını oluşturmak için bunları birbirine bağlayabilmemizdir ("zincirleme"):

 
order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }

Özel probleminize sözler uygulayalım. İstek mantığımızı, söz veren bir fonksiyonun içine saracağız:

 put_in_coffee

Aslında, yaptığımız tek şey drink_coffee'a yapılan çağrıya

var answer;
$.ajax('/foo.json') . done(function(response) {
  callback(response.data);
});

function callback(data) {
  console.log(data);
}
eklendi. Bu işe yarıyor, çünkü jQuery'nin then modeli şimdiden bir çeşit söz benzeri şey döndürüyor. (Uygulamada, ayrıntılara girmeden, bu aramayı gerçek bir söz vermek için sarmayı ya da order_milk'a alternatif bir seçenek kullanmayı tercih ederiz.) Şimdi, dosyayı yüklemek ve bitmesini beklemek istiyorsak ve sonra bir şeyler yapın, basitçe söyleyebiliriz  put_in_coffee

örneğin,

 then

Sözleri kullanırken,

order_milk() . then(put_in_coffee)
'a birçok işlevi geçtikten sonra, daha kompakt ES6 stili ok işlevlerini kullanmak genellikle yararlı olur:  
order_milk() . then(put_in_coffee) . then(drink_coffee)

function get_data() {
  return $.ajax('/foo.json');
}
anahtar sözcüğü

Ancak, senkronize olduğunda kodun bir yolunu, zamanuyumsuz ise oldukça farklı bir yolunu yazmak zorunda olduğu konusunda hâlâ tatmin edici olmayan bir şey var. Senkronize etmek için yazıyoruz

 return

ancak $.ajax asenkronize ise, sözlerle birlikte yazmalıyız

 $.ajax

Yukarıda, "JS'nin, ikincisini yürütmeden önce ilk aramanın bitmesi için beklemesinin gerektiğini bilmenin yolu yoktur" demiştik. JS'ye bunu söylemenin bir yolu olsaydı olsaydı iyi olmaz mıydı? Görünüşe göre - $.ajax anahtar sözcüğü, "async" işlevi olarak adlandırılan özel bir işlev türü içinde kullanılan. Bu özellik ES'nin yaklaşmakta olan versiyonunun bir parçası ancak önceden belirlenmiş Babil gibi transpillerde mevcut. Bu bize basitçe yazmamızı sağlar

 
get_data() . then(do_something)

Senin durumunda, böyle bir şey yazabilirsin

 
get_data() . 
  then(function(data) { console.log(data); });
    
28
2018-12-10 05: 52: 30Z

Elbette senkron istek, vaat gibi birçok yaklaşım var, ama deneyimlerime göre geri arama yaklaşımını kullanmalısın. Javascript’in eşzamansız davranışı doğaldır. Bu nedenle, kod snippet'iniz biraz farklı olabilir:

 then     
27
2018-03-07 14: 23: 16Z
  1. Geri aramalar veya JavaScript ile ilgili kendiliğinden eşzamansız bir şey yok.
    2018-03-18 19: 48: 53Z

Soru şuydu:

  

Yanıtı nasıl iade ederim?e zaman uyumsuz bir aramadan mı?

hangileri olarak yorumlanabilir:

  

Eşzamansız kodunun eşzamanlı görünmesi nasıl yapılır?

Çözüm, geri aramalardan kaçınmak ve Sözler ile zaman uyumsuz /beklemede kombinasyonunu kullanmak olacaktır.

Bir Ajax isteğine örnek vermek istiyorum.

(Javascript'te yazılabilmesine rağmen, Python'da yazmayı ve Transcrypt kullanarak Javascript'i derlemeyi tercih ediyorum. . Yeterince açık olacak.)

Önce JQuery kullanımını etkinleştirelim,

get_data() . 
  then(data => console.log(data));
’un async’a ulaşmasını sağlayın:  
a();
b();

Bir Söz döndüren bir işlev tanımlayın, bu durumda bir Ajax çağrısı:

 a

eşzamansız kodunu, eşzamanlı ymış gibi kullanın:

 
a() . then(b);
    
25
2018-05-24 08: 36: 33Z

Sözü Kullanma

Bu sorunun en mükemmel cevabı await kullanıyor.

 
async function morning_routine() {
  var milk   = await order_milk();
  var coffee = await put_in_coffee(milk);
  await drink(coffee);
}

Kullanım

 
async function foo() {
  data = await get_data();
  console.log(data);
}

Ama bekle ...!

Sözlerin kullanılmasında bir sorun var!

Neden kendi özel Sözümüzü kullanmalıyız?

Eski tarayıcılarda bir hata olduğunu bulana kadar bu çözümü bir süredir kullanıyordum:

 
function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            myCallback(response);
        }
    });

    return result;
}

function myCallback(response) {
    // Does something.
}

Bu nedenle, eğer tanımlanmamışsa, js derleyicileri için ES3'den aşağıya kendi Promise sınıfımı uygulamaya karar verdim. Bu kodu ana kodunuzdan önce ekleyin ve ardından Güvenle kullanın!

 $     
17
2019-05-28 10: 08: 52Z

Ağaçlara bakmadan önce ormanı görelim.

Burada ayrıntılı bilgi içeren birçok bilgilendirici cevap var, hiçbirini tekrar etmeyeceğim. JavaScript'te programlamanın anahtarı, öncelikle genel yürütmenin doğru zihinsel modeli 'ne sahip olmasıdır.

  1. Giriş noktalarınız bir etkinliğin sonucu olarak yürütülür. İçin Örneğin, tarayıcıya kod içeren bir script etiketi yüklenir. (Buna göre, bu yüzden endişelenmeniz gerekebilir. dom elemanlarını gerektiriyorsa, sayfanın kodunuzu çalıştırmaya hazır olması önce inşa edilecekler vs.)
  2. Kodunuz tamamlanmaya devam eder - ancak çoğu zaman uyumsuz çağrı yapar XHR de dahil olmak üzere, geri çağrılarınızın herhangi birini yürütmeden istekler, zaman aşımları, dom olay işleyicileri, vb. ayarlar. Yürütülmeyi bekleyen bu geri aramaların her biri bir sıraya oturur ve işten çıkarılan diğer olayların tümü tamamlandıktan sonra çalıştırılmalarını bekler.
  3. Her bir XHR isteğine yapılan her geri arama, zaman aşımı veya dom değerini ayarlar. bir kez çağrılan etkinlik daha sonra tamamlanacak.

İyi haber şu ki, eğer bu noktayı iyi anlarsanız, yarış koşulları hakkında asla endişelenmenize gerek kalmayacak. Öncelikle, en başta farklı ayrık olaylara cevap olarak kodunuzu nasıl düzenlemek istediğinize ve bunları nasıl bir mantıksal sıraya dizmek istediğinize ilişkin bir şey yapmalısınız. Bu amaç için araçlar olarak vaatler veya daha üst düzey yeni eşzamansız /beklemenizi kullanabilir ya da kendinize ait olanları alabilirsiniz.

Fakat bir problemi çözmek için asıl problem alanı ile rahat olana kadar taktiksel bir araç kullanmamalısınız. Ne zaman çalışması gerektiğini bilmek için bu bağımlılıkların bir haritasını çizin. Tüm bu geri aramalara geçici bir yaklaşım denemek sadece size iyi hizmet vermeyecektir.

    
14
2017-10-29 08: 36: 37Z

ES2017'yi kullanarak bunu işlev bildirimi olarak almalısınız.

 S

Ve böyle yürütmek.

 
__pragma__ ('alias', 'S', '$')

Veya Söz Sözdizimi

 
def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()
    
14
2018-01-24 06: 18: 55Z
  1. bu ikinci işlevi yeniden kullanılabilir hale getirebilir mi?
    2019-02-17 02: 02: 09Z
async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")
kaynak yerleştirildi İşte