Zaman uyumsuz bir çağrının yanıtını nasıl döndürürüm?
foo Ajax isteği yapan bir işleve sahibim . Yanıtı nasıl iade edebilirim foo ?
success Geri çağırmadaki değeri döndürmeyi ve işlev içindeki yerel bir değişkene yanıtı atamayı ve bunu döndürmeyi denedim , ancak bu yollardan hiçbiri yanıtı geri döndürmedi.
Felix Kling2013-01-082013-01-08 17:06:14Z
→ Farklı örneklerle eşzamansız davranışın daha genel bir açıklaması için, lütfen bkz. Değişkenim bir işlevin içinde değiştirdikten sonra neden değişmiyor? - Asenkron kod referansı
→ Sorunu daha önce anladıysanız, aşağıdaki olası çözümlere atlayın.
Bir de Ajax açılımı asenkron . Bu, isteğin gönderilmesi (veya daha doğrusu cevabın alınması) normal uygulama akışından alındığı anlamına gelir. Örnekte, $.ajax hemen geri döner ve bir sonraki ifade, geri arama olarak return result; ilettiğiniz işlev success çağrılmadan önce çalıştırılır .
Burada, senkronize ve senkronize olmayan akış arasındaki farkı daha net bir şekilde açıklayan bir benzetme şöyledir:
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.
Aynısı "normal" kod içeren bir işlev çağrısı yaptığınızda oluyor:
Yürütülmesi findItem uzun zaman alabilir olsa da, daha sonra gelen herhangi bir kod işlev sonucu döndürene kadar beklemek var item = findItem(); zorundadır .
Aynı sebepten dolayı arkadaşını tekrar ara. Ama bu sefer ona acelesi olduğunu ve seni cep telefonundan arayacağını söylemelisin . Telefonu kapat, evden ayrıl ve ne yapmayı planlıyorsan onu yap. Arkadaşınız sizi geri aradığında, size verdiği bilgilerle ilgileniyorsunuz.
Ajax isteğinde bulunduğunda olan tam olarak bu.
Yanıtı beklemek yerine, yürütme derhal devam eder ve Ajax çağrısından sonraki ifade yürütülür. Sonunda yanıtı almak için, yanıt alındı kez çağrılacak bir işlev, bir sağlamak geri arama (bildirim şey? Çağrı geri ?). Bu çağrıdan sonra gelen herhangi bir ifade, geri arama çağrılmadan önce gerçekleştirilir.
Neden soruyorsun kötü?
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şecektir.
Aşağıda, her biri üst üste inşa edilmiş üç farklı çözüme bakacağız:
Sözler async/await (ES2017 +, bir aktarıcı veya rejeneratör kullanıyorsanız, eski tarayıcılarda kullanılabilir)
Geri aramalar (düğümde popüler)
Sözler then() (ES2015 +, çok sayıda söz kütüphanesinden birini kullanıyorsanız, eski tarayıcılarda kullanılabilir)
Her üçü de mevcut tarayıcılarda ve düğüm 7 + 'da kullanılabilir.
ES2017 +: ile vaat ediyor async/await
2017'de yayınlanan ECMAScript sürümü , zaman uyumsuz işlevler için sözdizimi düzeyinde destek sağlamıştır. Yardımıyla async ve await bir "senkron tarzı" asenkron yazabilir. Kod hala eşzamansızdır ancak okunması / anlaşılması daha kolaydır.
async/await Bir vaat üzerine inşa: bir async fonksiyon her zaman bir söz verir. await Bir vaadi "çözer" ve ya vaadin çözüldüğü değerle sonuçlanır ya da vaat reddedilirse bir hata yapar.
Önemli: Yalnızca await bir async işlev içinde kullanabilirsiniz . Şu anda, üst düzey await henüz desteklenmiyor, bu nedenle bir bağlam başlatmak için bir zaman uyumsuz IIFE ( Anında Çağrılan İşlev İfadesi ) yapmanız gerekebilir async .
MDN async ve hakkında daha fazla bilgi edinebilirsiniz await .
İşte yukarıdaki gecikmenin üstüne çıkan bir örnek:
Mevcut tarayıcı ve düğüm sürümleri desteği async/await . Rejeneratörü (veya Babel gibi rejeneratör kullanan araçları) kullanarak kodunuzu ES5'e dönüştürerek daha eski ortamları da destekleyebilirsiniz .
İşlevlerin geri aramaları kabul etmesine izin ver
Geri çağırma, basitçe başka bir işleve geçen 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 iletilir.
Soru örneğinde, foo geri aramayı kabul edebilir ve success geri ara olarak kullanabilirsiniz . Yani bu
Burada "inline" fonksiyonunu tanımladık fakat herhangi bir fonksiyon referansını geçebilirsiniz:
callback foo biz onu çağırdığımızda ilettiğimiz fonksiyona atıfta bulunacağız ve basitçe onu kullanacağız success . Bir başka deyişle, Ajax talebi başarılı olduğunda, $.ajax cevap arayacak callback ve geri aramaya cevap verecektir (bununla geri dönüşü tanımlayacağımızdan bu adresten yararlanılabilir result ).
Yanıtı geri aramaya geçirmeden önce de işleyebilirsiniz:
Üçüncü taraf kodlarla çalışmak zorunda olduğunuzda zorluklar ortaya çıkabilir, ancak çoğu sorun yalnızca uygulama akışını düşünerek çözülebilir.
ES2015 +: O zamanlar vaat ediyor ()
Promise API ECMAScript'e 6 (ES2015) yeni bir özelliktir, ama iyi vardır tarayıcı desteği zaten. Standart Promises API'sini uygulayan ve asenkron fonksiyonların (örneğin bluebird ) kullanımını ve bileşimini kolaylaştırmak için ek yöntemler sağlayan birçok kütüphane de vardır .
Sözler gelecekteki değerler için kapsayıcıdır . Sözün değeri aldığında ( çözülür ) veya iptal edildiğinde ( reddedildiğinde ), bu değere erişmek isteyen tüm "dinleyicilerini" bildirir.
Düz geri aramalara göre avantajı, kodunuzu ayırmanıza izin vermesi ve oluşturması daha kolay olmasıdır.
İşte bir söz kullanmanın basit bir örneği:
Ajax çağrımıza uygulandığında şöyle sözler kullanabiliriz:
Teklif vaat eden tüm avantajları açıklamak, bu cevabın kapsamı dışındadır, ancak yeni bir kod yazarsanız, bunları ciddiye almalısınız. Kodunuzun mükemmel bir soyutlamasını ve ayrılmasını sağlarlar.
Ertelenen nesneler , jQuery'nin vaatlerin özel uygulamasıdır (Promise API standardize edilmeden önce). Neredeyse vaat ettikleri gibi davranırlar, ancak biraz farklı bir API gösterirler.
Her jQuery metodunun Ajax metodu, fonksiyonunuzdan sadece geri dönebileceğiniz bir "ertelenmiş nesne" (aslında ertelenmiş bir nesnenin vaadi) döndürür:
Yan not: Promise gotchas
Vaat edilen ve ertelenen nesnelerin gelecekteki bir değer için kaplar olduğunu, değerin kendisi olmadığını unutmayın. Örneğin, aşağıdakilere sahip olduğunuzu varsayalım:
Bu kod yukarıdaki eşzamansız sorunları yanlış anlıyor. Ö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 ifadenin her zaman bu Ertelenmiş nesneyi alacağı, onu olduğu true gibi kabul edeceği ve kullanıcı giriş yapmış gibi devam edeceği anlamına gelir . İyi değil.
Ancak düzeltme kolaydır:
Tavsiye edilmiyor: Senkron "Ajax" çağrıları
Bahsettiğim gibi, bazı (!) Zaman uyumsuz işlemlerin zaman uyumlu muadilleri var. Kullanımlarını savunmuyorum, ancak bütünlük uğruna, nasıl senkronize bir çağrı yapacağınız:
Doğrudan bir XMLHTTPRequest nesneyi kullanıyorsanız, false üçüncü bir argüman olarak iletin .open .
JQuery kullanıyorsanız , async seçeneği için ayarlayabilirsiniz false . Bu seçenek unutmayın kaldırılmış jQuery 1.8 beri. Daha sonra hala bir success geri arama kullanabilir veya jqXHR nesnesinin responseText özelliğine erişebilirsiniz :http://api.jquery.com/jQuery.ajax/%23jqXHR#jqXHR
Başka jQuery Ajax yöntemi gibi kullanırsanız $.get , $.getJSON vb, aşağıda belirtilen yerlere değiştirmek zorunda $.ajax (sadece yapılandırma parametreleri geçirebilirsiniz beri $.ajax ).
Önüne bak! Eşzamanlı bir JSONP isteği yapmak mümkün değildir . JSONP, doğası gereği, her zaman asenkrondir (bu seçeneği düşünmemek için bir neden daha).
Eğer ediyorsanız değil kodunuzda jQuery kullanarak, bu cevap size göre
Kodunuz, bu satırlar boyunca bir şey olmalıdır:
Felix Kling, AJAX için jQuery kullanan kişilere cevap yazma konusunda iyi bir iş yaptı, olmayan insanlara bir alternatif sunmaya karar verdim.
( Yeni fetch API, Angular veya aşağıda başka bir cevap eklediğim sözler kullananlar için ) dikkat edin.
Bu, diğer cevabın "Sorunun açıklaması" nın kısa bir özetidir, bunu okuduktan sonra emin değilseniz, bunu okuyun.
Bir AJAX açılımı asenkron . Bu, isteğin gönderilmesi (veya daha doğrusu cevabın alınması) normal uygulama akışından alındığı anlamına gelir. Örnekte, .send hemen geri döner ve bir sonraki ifade, geri arama olarak return result; ilettiğiniz işlev success çağrılmadan önce çalıştırılır .
Bu, geri döndüğünüzde, tanımladığınız dinleyici henüz çalışmadı, bu da döndürdüğünüz değerin tanımlanmadığı anlamına gelir.
a İade edilen değer undefined , a=5 parçanın henüz yürütülmediğinden beri . AJAX böyle 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 sorunun olası bir çözümü yeniden etkin olarak kodlamak ve hesaplama tamamlandığında programınıza ne yapacağınızı söylemek.
Buna CPS denir . Temel olarak, getFive tamamlandığında gerçekleştirecek bir eylemden geçiyoruz , kodumuza bir etkinlik tamamlandığında nasıl tepki vereceğimizi söylüyoruz (AJAX çağrımız gibi veya bu durumda zaman aşımı gibi).
Hangi "5" ekrana uyarmalıdır. (Keman) .
Bunu çözmenin temelde iki yolu var:
AJAX aramasını senkronize edin (SJAX olarak adlandıralım).
Geri aramalar ile düzgün çalışması için kodunuzu yeniden yapılandırın.
1. Senkron AJAX - Yapmayın !!
Senkron AJAX gelince, yapma! Felix'in cevabı, neden kötü bir fikir olduğu konusunda zorlayıcı tartışmalara yol açıyor. Ö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 alındığı hakkında kısa bir özet:
XMLHttpRequest, hem senkron hem de asenkron iletişimleri destekler. Ancak, genel olarak, zaman uyumsuz istekler, performans nedenlerinden dolayı senkronize istekler için tercih edilmelidir.
Kısacası, senkronize istekler kodun yürütülmesini engeller ... ... bu ciddi sorunlara neden olabilir ...
Eğer varsa sahip bunu yapmak için, bir bayrak geçirebilirsiniz: Bu şekilde yapılabilir:
İşleviniz bir geri aramayı kabul etsin. Örnek kodda foo bir geri aramayı kabul etmek için yapılabilir. Biz nasıl bizim kod söylüyorum olacak tepki zaman foo tamamlar.
Burada anonim bir işlevi geçtik, ancak mevcut bir işleve bir referansı kolayca ileterek şöyle görünmesini sağladık:
Bu tür bir geri arama tasarımının nasıl yapıldığına dair daha fazla ayrıntı için Felix'in cevabını kontrol edin.
Şimdi, foo'nun kendisini buna göre davranmasını tanımlayalım.
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 hareket ederek bunu daha da uzatabiliriz (bir başarısız işleyici ve benzeri oluşturabiliriz). Sorunumuzu etkin bir şekilde çözme.
Hala bunu anlamakta zorluk çekiyorsanız , MDN'deki AJAX başlangıç ​​kılavuzunu okuyun .
Benjamin Gruenbaum2013-05-292013-05-29 23:30:56Z
XMLHttpRequest 2 (her şeyden önce Benjamin Gruenbaum ve Felix Kling'in cevaplarını okuyun)
Eğer jQuery kullanmıyorsanız ve modern tarayıcılarda ve ayrıca mobil tarayıcılarda çalışan güzel bir kısa XMLHttpRequest 2 istiyorsanız, bu şekilde kullanmanızı öneririm:
Geri arama doğrudan ayarlanır (bu yüzden fazladan fazladan kapatma gerekmez).
Yeni aşırı yükü kullanır (bu nedenle, okuma sistemi durumunu ve durumunu kontrol etmeniz gerekmez)
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):
Veya bir nedenden dolayı bind() bir sınıfa geri arama yapmanız durumunda:
Veya (yukarıdakilerden daha iyisi anonim işlevler her zaman bir problemdir):
Daha kolay değil.
Ş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ınhttp://caniuse.com/xhr2
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 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ı kullanmak, onu kaybettiğiniz başka bir büyük hatadır, aksi halde onu kaybettiğiniz başka bir büyük hatadır.
Yine ... çok kısa bir işlev, ama alma ve gönderme.
Veya tam bir form elemanı ( document.getElementsByTagName('form') ) iletin :
Gördüğünüz gibi senkronizasyon yapmadım ... bu kötü bir şey.
Bunu söyledikten sonra ... neden kolay yoldan yapmıyorsun?
Yorumda da belirtildiği gibi, && senkronize hata kullanımı tamamen cevabı işaret ediyor. Ajax'ı uygun şekilde kullanmak için güzel bir kısa yol hangisidir?
Yukarıdaki komut dosyasında, statik olarak tanımlanmış bir hata işleyiciniz vardır, böylece işlevden ödün vermez. Hata işleyicisi diğer işlevler için de kullanılabilir.
Ancak gerçekten bir hatayı gidermek için tek yol yanlış bir URL yazmaktır; bu durumda her tarayıcı bir hata atar.
Hata işleyicileri, eğer özel başlıklar belirlerseniz, responseType'ı bir dizi arabellek ya da her neyse blob ...
'POSTAPAPAP' öğesini yöntem olarak geçseniz bile, hata atmaz.
'Fdggdgilfdghfldj' formdata olarak geçseniz bile, hata atmaz.
İlk durumda hata, displayAjax() altında this.statusText olduğu gibidir Method not Allowed .
İkinci durumda, sadece çalışır. Doğru gönderi verilerinden geçip geçmediğinizi sunucu tarafında kontrol etmeniz gerekir.
etki alanları arası izin verilmiyor, otomatik olarak hata veriyor.
Hata yanıtında hata kodu yoktur.
Sadece bir this.type tanesi hataya ayarlanmış.
Hatalar üzerinde tamamen kontrolünüz yoksa neden bir hata işleyicisi ekleyin? Geri arama işlevinde hataların çoğu bunun içinde döndürülür displayAjax() .
Yani: URL'yi düzgün bir şekilde kopyalayıp yapıştırabiliyorsanız hata kontrollerine gerek yok. ;)
Not: İ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 . Ben yedim
Bir süre tarayıcıyı engellemek istiyorsanız .txt senkronize güzel bir büyük dosya yükleyin .
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 istek için farklı işlevler kullanıyorsanı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 sayfa varsa. Bu durumda, biraz Ajax işlevini değiştirin ve b'yi özel işlevinizle değiştirin.
Fonksiyonu genişletmek istiyorsanız ...
Çok fazla API kullanıyorum ve her HTML sayfasına entegre ettiğim ilk işlevlerden biri bu cevabın ilk Ajax işlevi, 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ü düzenleyicileri dönüştürdüm, base64images içeren web SQL veritabanlarını doldurdum ve çok daha fazlası ... Ancak bu durumlarda sadece bunun için bir işlev oluşturmalısınız Amaç ... Bazen bir blob, dizi tamponları gerekir, başlıkları ayarlayabilir, mime tipini geçersiz kılabilir ve çok daha fazlası ...
Fakat buradaki soru, bir Ajax yanıtını nasıl iade edeceğimiz ... (Kolay bir yol ekledim.)
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 kütüphanesi anlamına gelir.
Felix Kling, jQuery kullanan kişilere AJAX'in geri çağrılarıyla cevap yazmak için 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.
Ne zaman söz veren bir yöntem çağırırsanız, then işleyiciler her zaman eşzamansız olarak yürütülür - bu, altlarındaki kodun ardından .then işleyicide bulunmaz .
Bu araçlar size iade ederken henüz yürütülmediği tanımladığınız işleyicisi. Bu da, döndürdüğünüz değerin zaman içinde doğru değere ayarlanmadığı anlamına gelir. data then
Değeri data olan undefined beri data = 5 parçası henüz infaz edilmemiştir. Muhtemelen bir saniyede gerçekleşecek, fakat o zamana kadar iade edilen değer ile ilgisi yok.
İşlem henüz gerçekleşmediğinden (AJAX, sunucu çağrısı, IO, zamanlayıcı), istek geri döndüğünde değeri geri döndürüyorsunuz, kodunuza bu değerin ne olduğunu söyleme şansınız var.
Bu sorunun olası bir çözümü yeniden etkin olarak kodlamak ve hesaplama tamamlandığında programınıza ne yapacağınızı söylemek. Sözler, doğada geçici (zamana duyarlı) olarak bunu aktif olarak mümkün kılar.
Sözlerde hızlı özetleme
Bir Söz, zaman içindeki bir değerdir . Vaatlerde devlet var, hiçbir değeri olmadan beklemeye başlıyorlar ve buna razı olabiliyorlar:
yerine hesaplama başarıyla tamamlandı anlamına gelir.
Hesaplamanın başarısız olduğu anlamına gelen reddedildi .
Bir söz, ancak bir kez durumları değiştirebilir ; bundan sonra daima aynı durumda kalır. then Değerlerini almak ve hataları ele almak için sözler ekleyebilirsiniz . then işleyiciler çağrıların zincirlenmesini sağlar . Sözler, geri dönen API'ler kullanılarak oluşturulur . Örneğin, daha modern AJAX değişimi fetch veya jQuery'nin $.get geri dönüşü vaat ediyor.
Bir .then söz verdiğimizde ve ondan bir şey iade ettiğimizde - 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.
Yukarıdaki konuyu vaatlerle nasıl çözebileceğimizi görelim. Öncelikle, bir gecikme işlevi oluşturmak için Promise yapıcısını kullanarak yukarıdan vaat eden devletler hakkındaki anlayışımızı gösterelim :
Şimdi setTimeout'u vaatleri kullanmak then üzere dönüştürdükten sonra, saymak için kullanabiliriz :
Temel olarak, bir dönen yerine değerini biz çünkü eşzamanlılık modeli yapamaz - bir geri dönüyoruz sarmalayıcı biz ki bir değeri paketini ile then . Açabileceğin bir kutu gibi then .
Bu, orijinal API çağrınız için aynı kalır:
Yani bu aynı şekilde çalışır. 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, zaman uyumsuz bir çağrıdan yanıtın nasıl döndürüleceğini biliyoruz.
ES6 , ortada dönebilen ve sonra bulundukları noktaya devam edebilen fonksiyonlar olan jeneratörleri tanıtır . Bu genellikle diziler için kullanışlıdır, örneğin:
Bir yineleyiciyi 1,2,3,3,3,3,.... yinelenebilen dizinin üzerine döndüren bir işlevdir . Bu kendi başına ilginç olsa da ve bir çok olasılık için odayı açıyorsa, belli bir ilginç vaka var.
Ürettiğimiz dizi, sayılar yerine bir eylemler dizisiyse - bir eylem gerçekleştirildiğinde işlevi duraklatabilir ve işlevi sürdürmeden önce onu bekleyebiliriz. Dolayısıyla, bir sayı dizisi yerine gelecekteki değerler dizisine ihtiyacımız var - yani: sözler.
Bu biraz zor ama çok güçlü bir numara, senkronize olmayan bir şekilde asenkron kod yazmamıza izin veriyor. Bunu sizin için yapan birkaç "koşucu" var, birini yazmak kısa bir kod satırı ama bu cevabın kapsamı dışında. Promise.coroutine Burada Bluebird's'i kullanacağım , ama co ya da gibi başka paketleyiciler var Q.async .
Bu yöntem, diğer coroutinler'den alabileceğimiz bir söz veriyor. Örneğin:
ES7'de, bu daha da standardize edilmiştir, şu anda birkaç teklif var ancak hepsinde await söz verebilirsiniz . Bu sadece yukarıdaki ES6 teklifi için async ve await anahtar kelimeleri ekleyerek "şeker" (daha iyi sözdizimi) 'dir . Yukarıdaki örneği yapmak:
Hala aynı söz verir :)
Benjamin Gruenbaum2015-05-122015-05-12 02:22:57Z
Ajax'ı yanlış kullanıyorsunuz. Buradaki fikir, herhangi bir şey döndürmesini değil, verileri verileri işleyen bir geri çağırma işlevi adı verilen bir öğeye teslim etmektir.
Gönderim işleyicisinde herhangi 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.
Hemant Bavle2014-02-182014-02-18 18:58:37Z
Korkunç görünümlü, elle çizilmiş bir çizgi romanla cevap vereceğim. İkinci resim nedeni budur result olduğunu undefined sizin kod örneğinde.
Johannes Fahrenkrug2016-08-112016-08-11 14:17:36Z
AngularJS kullananlar için bu durumu kullanarak halledebilirsiniz Promises .
İşte diyor ki
Sözler eşzamanlı olmayan eşzamansız işlevlerde kullanılabilir ve birinin birden çok işlevi birlikte zincirlemesine izin verir.
Burada ayrıca güzel bir açıklama bulabilirsiniz .
Aşağıda belirtilen belgelerde bulunan örnek .
Açısal2 ve Sonra
In Angular2 aşağıdaki örnekte bakmak, ama onun ile önerilen kullanımına Observables sahip Angular2 .
Bunu bu şekilde tüketebilirsiniz,
Orijinal yayını burada görün . Ancak Typescript yerel es6'yi desteklemiyor Promises , kullanmak istiyorsanız, bunun için bir eklentiye ihtiyacınız olabilir.
Ek olarak, burada tanımlanmış olan sözler spec .
Maleen Abewardana2014-08-262014-08-26 08:11:36Z
Buradaki yanıtların çoğu, tek bir zaman uyumsuz işleminiz olduğunda faydalı önerilerde bulunur, ancak bazen bu , bir dizideki veya diğer liste benzeri yapıdaki her giriş için zaman uyumsuz bir işlem yapmanız gerektiğinde ortaya çıkar . Temptation bunu yapmaktır:
İşe yaramazlığın nedeni doSomethingAsync , sonuçları kullanmaya çalıştığınız zaman gelen geri aramaların henüz başlatılmadığıdır.
Bu nedenle, 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 (üst üste binen) veya seri olarak (sırayla arka arkaya) yapın.
Hepsini başlatabilir ve kaç tane geri arama beklediğinizi takip edebilir ve ardından o kadar geri arama aldığınızda sonuçları kullanabilirsiniz:
(Yapabiliriz expecting ve sadece kullanabilirdik results.length === theArray.length , ama bu bizi theArray çağrılar sıra dışıyken değiştirilme ihtimaline açık bırakır ...)
Sonuçları sıralı olmasa bile (sonuçları zaman uyumsuz çağrılar başlatıldıkları sırayla tamamlamadıklarından), ilgili girdiyle aynı konumda kaydetmek için index ' forEach yi nasıl kullandığımıza dikkat edin results .
Peki ya bu sonuçları bir fonksiyondan döndürmeniz gerekirse ? Diğer cevapların işaret ettiği gibi; fonksiyonunuzun bir geri aramayı kabul etmesi ve çağırması (veya bir Sözü geri vermeniz ) gerekir. İşte bir geri arama sürümü:
Veya Promise bunun yerine dönen bir sürümü :
Elbette, eğer doSomethingAsync bize hatalar geçerse, reject bir hata olduğunda söz vermeyi reddetmek için kullanırız.)
(Ya da dönüşümlü olarak, bunun karşılığında doSomethingAsync bir söz verebilir, bir söz verebilir ve sonra aşağıdakileri yapabilirsiniz ...)
Eğer doSomethingAsync size verir Promise , şunları kullanabilirsiniz Promise.all :
doSomethingAsync Bunun ikinci ve üçüncü bir argümanı görmezden geleceğini biliyorsanız, doğrudan doğrudan şuna iletebilirsiniz map ( map geri çağrısını üç argümanla çağırır, ancak çoğu kişi yalnızca ilkini kullanır):
Not Promise.all sözünü hepsi çözüldükten sonra bunu vermek sözlerin hepsi sonuçlarının bir dizi sözünü giderir veya reddeder zaman ilk bunu reddeder vermek sözlerin.
İş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 sonuçla geri arama yapan bir fonksiyonun örneği:
(Çalışmayı seri olarak yaptığımızdan, results.push(result) sıralı sonuçları alamayacağımızı bildiğimiz için kullanabiliriz . Yukarıdakilerde kullanabilirdik results[index] = result; , ancak aşağıdaki örneklerin bazılarında bir dizine sahip değiliz) kullanmak.)
(Veya, yine, bunun için bir sarıcı oluşturun doSomethingAsync , size bir söz verin ve aşağıdakileri yapın ...)
Eğer doSomethingAsync size Sözü verir size (belki gibi bir transpiler ile ES2017 + sözdizimini kullanabilirsiniz eğer, Babil ), bir kullanabilir async fonksiyonu ile for-of ve await :
ES2017 + sözdizimini (henüz) kullanamıyorsanız, "Söz azaltma" modelinde bir varyasyon kullanabilirsiniz (bu, söz verilen söz azaltma yönteminden daha karmaşıktır; çünkü sonucu bir başkasına aktarmıyoruz , bunun yerine sonuçlarını bir dizide toplamak):
... ES2015 + ok işlevleriyle daha az hantal olan :
T.J. Crowder2017-05-032017-05-03 16:59:06Z
Şu örneğe bir göz atın:
Gördüğünüz gibi getJoke olan bir dönen çözülmesi söz (döndürürken çözülene res.data.value ). Böylece $ http.get isteği tamamlanıncaya kadar bekleyin ve sonra konsol.log (res.joke) yürütülür (normal bir asenkron akış olarak).
ES6 yolu (zaman uyumsuz - bekliyor)
Francisco Carmona2016-06-022016-06-02 08:31:13Z
Yani kullanıyorsanız açısal, Tepki veya yapmak başka çerçeveler iki yolu veri bağlama veya mağaza konsepti çok kolay kelimeyle bu sorun sadece sizin için sabittir, sizin sonucudur undefined sahipsin, böylece ilk aşamada result = undefined aldığınız önce veriyi ve sonucu alır almaz, güncellenecek ve Ajax çağrınızın cevabını veren yeni değere atanacaktır ...
Örneğin, sizin için işlemek için bir geri arama , söz ve son zamanlarda gözlemlenebilir olan bir geri arama kullanabilirsiniz ; örneğin , verileriniz sizin için hazır olduğunda , gözlemlenebilir olarak geri çağırma veya abone işlevi gibi bazı işlevlere sahip olduğumuz success() veya then() gerçekleştireceğimiz sözlerde .
Örneğin , jQuery kullanıyorsanız , bunun gibi bir şey yapabilirsiniz:
Bu async işlemlerini gerçekleştirmenin daha yeni yolları olan vaatler ve gözlemlenebilirler hakkında daha fazla bilgi çalışması için.
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 nesneye geçmektir.
İşte aynı bir örnek:
result Eşzamansız işlem sırasında değeri depolamak için nesneyi kullanıyorum . Bu, sonucun zamanuyumsuz işten sonra bile kullanılabilir olmasını sağlar.
Bu yaklaşımı çok kullanırım. Sonucun ardışık modüller aracılığıyla kablolanmasının söz konusu olduğu yerlerde bu yaklaşımın ne kadar iyi çalıştığını bilmek isterdim.
Sözler ve geri aramalar birçok durumda iyi çalışıyor olsa da, arkada şöyle bir şey ifade etmek acı vericidir:
Sonunda içinden geçeceksin async1 ; name tanımsız olup olmadığını kontrol edin ve uygun şekilde geri arama çağırın.
Küçük örneklerde sorun yok olsa da, pek çok benzer durumunuz ve hata işlemeniz olduğunda sinir bozucu olur.
Fibers sorunun çözümünde yardımcı olur.
Projeyi buradan kontrol edebilirsiniz .
Kısa cevap, şöyle bir geri arama yapmanız gerekiyor:
Pablo Matias Gomez2016-04-222016-04-22 14:47:08Z
Yazdığım aşağıdaki örnek nasıl yapılacağını gösteriyor
Eşzamansız HTTP çağrılarını yönetin;
Her bir API çağrısından yanıt bekleyin;
Promise kalıbı kullanın ;
Birden fazla HTTP çağrısına katılmak için Promise.all desenini kullanın ;
Bu çalışma örneği kendi kendine yetendir. XMLHttpRequest Arama yapmak için pencere nesnesini kullanan basit bir istek nesnesini tanımlayacaktır . Bir sürü sözün tamamlanmasını beklemek için basit bir işlev tanımlayacaktır.
Bağlam. Örnek, belirli bir sorgu dizesi kümesi için nesneleri aramak için Spotify Web API uç noktasını playlist sorguluyor:
Her bir öğe için yeni bir Söz, bir bloğu ateşler - ExecutionBlock sonucu ayrıştırır, sonuç dizisini temel alan, Spotify user nesnelerinin bir listesi olan ve yeni HTTP çağrısını ExecutionProfileBlock eşzamansız olarak yürüten bir dizi sonuç zamanlar .
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 sonuçları her çağrı alt grubundan birleştirebilirsiniz Promise.all .
NOT Son Spotify search API'leri, istek başlıklarında belirtilecek bir erişim belirteci gerektirecektir:
Bu nedenle, aşağıdaki örneği çalıştırmanız için erişim belirtecinizi istek başlıklarına koymanız gerekir:
Bu çözümü burada çok tartışmıştım .
2017 cevabı: şimdi her mevcut tarayıcıda ve düğümde tam olarak ne istersen yapabilirsin
Bu oldukça basit:
Bir söz ver
'Async' anahtar sözcüğünü ana işlevine ekleyin
İşte kodunuzun çalışan bir sürümü:
Bekleyen tüm geçerli tarayıcılarda ve düğüm 8'de desteklenir
Uzaktan arama yapmak için bu özel kütüphaneyi (Promise kullanılarak yazılmış) kullanabilirsiniz.
Basit kullanım örneği:
Vinoth Rajendran2016-05-262016-05-26 13:26:40Z
Bu basit bir senkronize fonksiyon çağrısı (her kod satırının bir sonraki sırada olandan önce 'işi ile bittiği') ve sonuç beklendiği gibi aynı.
Şimdi, fonksiyonumuza küçük bir gecikme ekleyerek biraz kod ekleyelim, böylece tüm kod satırları sırayla 'bitmedi'. Böylece, asenkron işlevin davranışını taklit eder:
Öyleyse işte, bu gecikme beklediğimiz işlevselliği bozdu! Ama tam olarak ne oldu? Eh, koda bakarsanız oldukça mantıklı. işlev foo() yürütme sonrasında hiçbir şey döndürmez (bu nedenle döndürülen değer şudur undefined ), ancak 1 saniye sonra 'wohoo' işlevini döndürmek için bir işlev yürüten bir zamanlayıcı başlatır. Ama gördüğünüz gibi, çubuğa atanan değer, daha sonra gelen başka bir şey değil, foo () 'dan derhal geri gönderilen şeylerdir.
Peki bu konuyla nasıl başa çıkacağız?
Fonksiyonumuzu bir PROMISE için soralım . 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:
Bu nedenle, özet - ajax tabanlı çağrılar vb. Gibi asenkron işlevlerin üstesinden gelmek için resolve , değere (geri dönmek istediğiniz) söz verebilirsiniz . Bu nedenle kısaca size çözmek yerine değerini dönen asenkron fonksiyonlarda.
GÜNCELLEME (Async / bekliyor ile vaat ediyor)
Vaatlerle then/catch çalışmaktan başka bir yaklaşım daha var. Fikir etmektir zaman uyumsuz bir işlevi tanımak ve sonra vaat bekleyin kod sonraki satıra geçmeden önce, gidermek için. Hala promises kaputun altında, ama farklı bir sözdizimsel yaklaşımla. İşleri netleştirmek için, aşağıda bir karşılaştırma bulabilirsiniz:
sonra / sürüm yakalamak:
async / bekliyor sürümü:
Anish K.2017-10-312017-10-31 20:12:45Z
Diğer bir çözüm, kodu sıralı uygulayıcı nsynjs aracılığıyla çalıştırmaktır .
Altta yatan fonksiyon söz veriliyorsa
nsynjs tüm sözleri ardışık olarak değerlendirecek ve söz sonucunu data mülkiyete sokacak :
Temel fonksiyon söz verilmezse
Adım 1. Geri çağırma işlevini nsynjs-farkında sarmalayıcıya sarın (söz verilmiş sürümü varsa, bu adımı atlayabilirsiniz):
Adım 2. Fonksiyona senkron mantığı yerleştirin:
Adım 3. nsynjs ile fonksiyonu senkronize bir şekilde çalıştırın:
Nsynjs, bazı yavaş fonksiyonların sonuçlarının hazır olmaması durumunda yürütmeyi duraklatan tüm operatörleri ve ifadeleri adım adım değerlendirecek.
Burada daha fazla örnek: https://github.com/amaksr/nsynjs/tree/master/examples
Js tek dişlidir.
Tarayıcı üç bölüme ayrılabilir:
1) Olay Döngüsü
2) Web API'si
3) Etkinlik Kuyruğu
Olay Döngüsü sonsuza kadar sürüyor, yani sonsuz türden bir döngü var.Event Queue, tüm işlevlerinizin bir olaya itildiği (örnek: klik) bu, sıradan yürütülen ve bu işlevi yürüten ve kendini hazırlayan Olay döngüsüne yerleştirilen teker tekerdir. ilki birinciden sonra bir tane yürütülür. Bu, bir işlevin yürütülmesi, sıradaki olay döngüsünde yürütülene kadar işlevin başlatılamayacağı anlamına gelir.
Şimdi sıradaki iki işlevi ittiğimizi düşünelim, biri sunucudan veri almak için diğeri bu verileri kullanır. Biz sıradaki serverRequest () işlevini önce iterek sonra da useiseData () işlevini ittik. serverRequest işlevi olay döngüsüne gider ve sunucudan veri almak için ne kadar zaman alacağımızı asla bilmediğimizden sunucuya çağrı yapar, bu nedenle bu işlemin zaman alması beklenir ve böylece olay döngüsümüzü meşgul ederiz, bu nedenle sayfamıza asılır; API, bu işlevi olay döngüsünden alır ve sunucuyu olay döngüsünü serbest hale getirir, böylece sıradaki işlevden sonraki işlevi çalıştırabiliriz. Sıradaki işlev, döngü içine giren ancak uygun veri olmadığı için döner. israf ve sonraki fonksiyonun yürütülmesi kuyruğun sonuna kadar devam eder. (Buna Async çağrısı denir, yani veri alana kadar başka bir şey yapabiliriz)
ServerRequest () işlevimizin bir kodda bir return ifadesi olduğunu varsayalım, sunucudan 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 hiçbir işlev olmadığından verilerini kullanamayız. Bu nedenle, Async Çağrısından bir şey döndürmek mümkün değildir.
Böylece bunun için çözüm geri arama veya sözdür .
Buradaki cevaplardan birinden bir görüntü, Geri arama kullanımını doğru şekilde açıklıyor ... Çağrılan sunucuyu işlevimize (sunucudan döndürülen verileri kullanan işlev) veriyoruz.
Kodumda buna denir.
Zaman uyumsuz arama yapmak için ECMA'daki (2016/17) yeni yöntemler için burayı okuyun (@Felix Kling'in Yanıtı) https://stackoverflow.com/a/14220323/7579856
Aniket Jha2018-02-032018-02-03 06:06:53Z
ECMAScript 6, asenkron bir tarzda kolayca programlamanıza izin veren 'jeneratörlere' sahiptir.
Yukarıdaki kodu çalıştırmak için şunu yapın:
ES6'yı desteklemeyen tarayıcıları hedeflemeniz gerekirse, ECMAScript 5'i oluşturmak için kodu Babel veya closure compiler aracılığıyla çalıştırabilirsiniz.
Geri arama ...args , 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, fs düğümü ile :
Asenkron isteklerle çalışmak için bazı yaklaşımlar:
Tarayıcı Promise nesnesi
Geri arama kavramının kullanılması - İlk cevapta uygulama olarak
Örnek: jQuery birden çok istekle çalışmak için ertelenen uygulama
Mohan Dere2016-08-132016-08-13 09:36:41Z
Kısa cevap : foo() Metodunuz derhal geri döner, $ajax() çağrı işlev döndükten sonra senkronize olmayan bir şekilde yürütülür . Asıl sorun, zaman uyumsuz çağrı tarafından alınan sonuçların geri döndüğünde nasıl veya nereye kaydedileceğidir.
Bu iş parçacığında çeşitli çözümler verilmiştir. Belki de en kolay yol, bir nesneyi foo() yönteme aktarmak ve sonuçları eşzamansız çağrı tamamlandıktan sonra bu nesnenin bir üyesinde saklamaktır.
Aramaya foo() devam etmenin yine de yararlı bir şey olmayacağını unutmayın . Ancak, zaman uyumsuz arama sonucu şimdi içinde saklanır result.response .
David R Tribble2015-09-232015-09-23 22:52:03Z
Başarı callback() içinde bir işlev kullanın foo() . Bu şekilde dene. Basit ve anlaşılması kolaydır.
Mahfuzur Rahman2017-04-242017-04-24 08:09:03Z
Kendimizi "zaman" olarak adlandırdığımız bir boyutta ilerleyen görünen bir evrende buluyoruz. 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 düşünün. 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:
JS o gerektiğini bilmenin bir yolu olmadığı için beklemek için order_milk çalışmasından önce sona put_in_coffee . Başka bir deyişle, o bilmiyor order_milk olan asenkron gelecekteki bir süre kadar sütün neden gitmiyor --is şey. JS ve diğer bildirici diller, birbirini beklemeden birbiri ardına yürütür.
JS'nin, çevreye atılabilecek birinci sınıf nesneler olarak işlevleri desteklemesi gerçeğinden faydalanan klasik JS yaklaşımı, bir işlevi bir işlevi bir asenkron isteğe bir parametre olarak geçirerek, daha sonra tamamlandığında çağıracaktır. Gelecekte görevini. Bu "geri arama" yaklaşımıdır. Bu gibi görünüyor:
order_milk başladı, süt siparişi verdi, sonra, ne zaman ve ne zaman gelirse, onu çağırıyor put_in_coffee .
Bu geri çağırma yaklaşımındaki sorun, sonucunu bildiren bir işlevin normal anlambilimini kirletmesidir return ; 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:
put_in_coffee hem içine koymak için hem de süte geçtiğimde, hem de süt konulduktan sonra uygulanacak eylem ( drink_coffee ). Bu kodları yazmak, okumak ve hata ayıklamak zorlaşıyor.
Bu durumda, sorudaki kodu şu şekilde yeniden yazabiliriz:
Bu, bir tür geleceği veya asenkron bir sonucu temsil eden belirli bir değer türü olan “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 then , sözün temsil ettiği sonuç gerçekleştiğinde gerçekleştirilecek bir eylemi geçirdiğiniz adlı tek bir yöntemi vardır.
Süt ve kahvelerimizde, order_milk gelen süt için bir söz vermek üzere tasarlıyoruz , ardından put_in_coffee bir then eylem olarak belirtiyoruz:
Bunun bir avantajı, gelecekteki oluşumların dizilerini ("zincirleme") oluşturmak için bunları birbirine bağlayabilmemizdir:
Özel probleminize sözler uygulayalım. İstek mantığımızı söz veren bir fonksiyonun içine saracağız:
Aslında yaptığımız tek şey return çağrıya bir şey eklemek $.ajax . Bu işe yarıyor, çünkü jQuery $.ajax zaten bir çeşit vaat tarzı şey döndürüyor. (Uygulamada, ayrıntılara girmeden, bu aramayı gerçek bir söz vermek için sarmayı tercih ederiz veya buna alternatif bir yöntem kullanırız $.ajax .) Şimdi, dosyayı yüklemek ve bitmesini beklemek istiyorsak, o zaman bir şeyler yap, basitçe söyleyebiliriz
then Vaatleri kullanırken, birçok fonksiyonun içine geçiyoruz , bu nedenle daha kompakt ES6 tarzı ok fonksiyonlarını kullanmak genellikle yararlı olur:
async anahtar kelime
Ancak yine de, senkronize olduğunda bir şekilde kod yazmak zorunda kalması ve zamanuyumsuz olarak oldukça farklı bir şekilde yapılması konusunda tatmin edici olmayan bir şey var. Senkron için, biz yazıyoruz
fakat eğer a asenkronize ise, sözlerle birlikte yazmak zorundayız.
Yukarıda, “JS'nin, ikincisini yürütmeden önce ilk çağrının bitmesini beklemesinin gerekmediğini bilmenin bir yolu olmadığını” dedik . Orada eğer hoş olmaz idi o JS anlatmak için bir yol? Var olduğu ortaya çıktı - await anahtar kelime, "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
Senin durumunda, böyle bir şey yazabilirsin
Khoa Bui2017-07-052017-07-05 20:28:42Z
hangi olarak yorumlanabilir:
Nasıl yapmak için asenkron kod bakmak senkron ?
Çözüm, geri aramalardan kaçınmak ve Promises ve async / await kombinasyonunu kullanmak olacaktır .
Bir Ajax talebi için bir örnek vermek istiyorum.
İlk önce JQuery kullanımını etkinleştirelim, şöyle olması $ mümkün S :
Söz veren bir işlev tanımlayın , bu durumda bir Ajax çağrısı:
Kullanım asenkron o sanki kodu senkron :
Pieter Jan Bonestroo2018-01-132018-01-13 19:13:20Z
Bu sorunun en mükemmel cevabı kullanıyor Promise .
Vaatleri kullanmada bir sorun var!
Neden kendi özel Sözümüzü kullanmalıyız?
Eski tarayıcılarda bir hata olduğunu bulana kadar bir süre bu çözümü kullanıyordum:
Bu yüzden, eğer tanımlanmamışsa , ES3 için kendi Promise sınıfımı, js derleyicilerinin altında uygulamaya karar verdim . Bu kodu ana kodunuzdan önce ekleyin ve güvenli bir şekilde Promise kullanın!
Amir Forsati2018-12-072018-12-07 14:10:23Z
Size kod yazmak yerine, JS'nin geri aramaları ve eşzamansızlığı nasıl ele aldığını anlamak için anahtar olan 2 kavram vardır. (bu bir kelime bile mi?)
Olay Döngüsü ve Eşzamanlılık Modeli
Dikkat etmeniz gereken üç şey var; Kuyruk; olay döngüsü ve yığın
Geniş, basit terimlerle, olay döngüsü proje yöneticisi gibidir, sıra ile yığın arasında çalıştırmak ve iletişim kurmak isteyen tüm fonksiyonları sürekli olarak dinler.
Bir şeyi çalıştırmak için bir mesaj aldığında, onu sıraya ekler. Sıra, yürütmeyi bekleyenlerin listesidir (AJAX isteğiniz gibi). böyle düşünün:
Bu mesajlardan biri çalıştırılacaksa, mesaj kuyruğundan çıkar ve bir yığın oluşturur, yığın mesajın talimatını yerine getirmek için JS'nin yürütmesi gereken her şeydir. Yani bizim örneğimizde aramak için söyleniyor foobarFunc
Bu yüzden foobarFunc uygulamasının çalışması gereken her şey (bizim durumumuzda anotherFunction ) yığına itilir. yürütüldü ve sonra unutuldu - olay döngüsü daha sonra sıradaki bir sonraki şeye geçecektir (veya mesajları dinler)
Buradaki kilit şey, yürütme emridir. Yani
WHEN kaçacak bir şey
Büyük soru ne zaman yanıt alacağı? Cevap bilmiyoruz - bu yüzden olay döngüsü bu mesajın "hey koş beni" demesini bekliyor. Eğer JS bu mesaj için eşzamanlı olarak bekleseydi, uygulamanız donar ve emer. Böylece JS, sıradaki iletinin sıraya eklenmesini beklerken sıradaki bir sonraki öğeyi çalıştırmaya devam eder.
Bu yüzden zaman uyumsuz işlevlerde geri arama denilen şeyleri kullanıyoruz . Kelimenin tam anlamıyla bir söz gibi . Bir noktada bir şeyi iade edeceğime söz verdiğim gibi, jQuery deffered.done deffered.fail ve deffered.always diğerlerinin yanı sıra belirli geri aramaları kullanıyor . Hepsini burada görebilirsinizhttps://api.jquery.com/category/deferred-object/
Yani yapmanız gereken şey, kendisine iletilen verilerle bir noktada yürütmeye söz verilen bir işlevi geçmek.
Bir geri çağırma hemen yürütülmediğinden, ancak daha sonraki bir zamanda, başvuruyu yürütülmeyen işleve iletmek önemlidir. yani
böylece çoğu zaman (ama her zaman değil) size geçmek olacak foo değil foo()
Umarım bu biraz mantıklı olur. Böyle kafa karıştırıcı görünen bir şeyle karşılaştığınızda - en azından anlamanız için belgeleri tamamen okumanızı tavsiye ederim. Seni çok daha iyi bir geliştirici yapacaktır.
Matthew Brent2018-05-042018-05-04 15:56:07Z
ES2017'yi kullanarak bunu işlev bildirimi olarak almalısınız.
Ve bu şekilde yürütmek.
Veya söz sözdizimi
Fernando Carvajal2018-01-242018-01-24 06:18:55Z
Bir diziden rastgele nasıl seçim yapabilirim?
Zaman uyumsuz bir geri çağırma işlevinden değer nasıl döndürülür? [çift]
Flask görünümünden JSON yanıtını döndür
Günlük dosyasını bir Android cihazdan nasıl edinebilirim?
Temel sınıftan çağrıldığında GetType () en çok türetilmiş türü döndürür mü?
Açısal 2: Etiketleri kullanıcıya göstermeden HTML'i JSON yanıtından nasıl oluşturursunuz? [çift]
ASP.NET MVC işleminden HTTP 404 yanıtı göndermenin doğru yolu nedir?
Açısal bir Gözlemlenebilir / http / asenkron çağrıdan gelen yanıtı nasıl geri gönderirim?
Sınıf adını genişletilmiş bir PHP sınıfındaki statik bir çağrıdan nasıl alabilirim?
Java'daki bir diziden nesneleri nasıl kaldırabilirim?
Yerel dosyaların üzerine “git pull” u nasıl zorlarım?
.NET'te bir biçim dizesinde kaşlı ayraçlar (küme parantezleri) nasıl kullanılır
Düz İngilizce olarak Monad? (FP arka planı olmayan OOP programcısı için)
Bir const dizisi bildir
'IIS APPPOOL \ ASP.NET v4.0' kullanıcısı için giriş başarısız oldu
Tamamen işlevsel programlama etkinliği
Java 8 paralel akışında özel iş parçacığı havuzu
FFmpeg kullanarak iki MP4 dosyası nasıl birleştirilir?
Paket adı için eşleşen bir istemci bulunamadı (Google Analytics) - birden çok ürünFlavors ve buildTypes [kapalı]
$ NON-NLS-1 $ ne anlama geliyor?