JavaScript ne zaman senkronize edilir?


202

Ben JavaScript her zaman eşzamansız olduğu izlenimi altında bulundum. Ancak, bunun olmadığı durumlar olduğunu öğrendim (yani DOM manipülasyonları). Ne zaman senkronize olacağı ve ne zaman asenkronize olacağı konusunda iyi bir referans var mı? JQuery bunu hiç etkiler mi?


14
Her zaman ajax hariç.
defau1t

Kabul edilen cevap yanlış ve yanlış yönlendiriyor, lütfen kontrol edin.
Suraj Jain

2
Ayrıca izlerken faydalı oldu youtube.com/watch?v=8aGhZQkoFbQ olay döngü anlamak ve nasıl yığını, web API'leri ve senkronizasyon ve zaman uyumsuz açısından görev kuyruğu çalışma
mtpultz

1
@ defau1t Bu yanlış değil, JavaScript her zaman eşzamanlıdır, ajax araması bittiğinde geri arama kuyruğa girer, java komut dosyasının eşzamanlı doğası nasıl bir istisnadır.
Suraj Jain

Yanıtlar:


281

JavaScript her zaman senkronize ve tek iş parçacıklıdır. Bir sayfada JavaScript kod bloğu yürütüyorsanız, o sayfada başka hiçbir JavaScript yürütülmez.

JavaScript, örneğin Ajax çağrıları yapabilmesi açısından eşzamansızdır. Ajax çağrısı yürütmeyi durduracak ve çağrı geri gelene kadar (başarılı veya başka bir şekilde) diğer kod yürütülebilecek ve bu noktada geri arama eşzamanlı olarak çalışacaktır. Bu noktada başka hiçbir kod çalışmaz. Şu anda çalışan başka bir kodu kesintiye uğratmaz.

JavaScript zamanlayıcıları aynı tür geri arama ile çalışır.

JavaScript'i eşzamansız olarak tanımlamak belki de yanıltıcıdır. JavaScript'in çeşitli geri çağrı mekanizmalarıyla senkronize ve tek iş parçacıklı olduğunu söylemek daha doğru olur.

jQuery, Ajax çağrılarında onları senkronize hale getirmek için bir async: falseseçenek sunar ( seçenekle). Yeni başlayanlar bunu yanlış kullanmaya eğilimli olabilir, çünkü daha alışılmış olabilecek daha geleneksel bir programlama modeline izin verir. Sorunlu olmasının nedeni, bu seçeneğin, tüm olay işleyicileri ve zamanlayıcıları dahil, sayfadaki tüm JavaScript'i bitirmesini engellemesidir .


31
üzgünüm, bu ifade "çağrı geri dönünceye kadar (başarıyla veya hata) kodu yürütmeyi durduracak oldukça anlamadım." detaylandırabilir misin? "Çalışmakta olan herhangi bir kodu kesintiye uğratmayacak" dediğinizde bu ifade nasıl doğru olabilir; Sadece ilk ifadede geri arama kodlarından mı bahsediyorsunuz? Lütfen beni aydınlat.
krishna

2
Nettuts, buradaki asenkronun
RobW

26
@cletus "Durdurulana kadar kodun yürütülmesini durduracak" ifadesinin yürütme durmadığından düzeltilmesi gerekiyor. Kod yürütme devam edebilir. Aksi takdirde, çağrının senkron olduğu anlamına gelir.
HS.

1
Ben de bu ifadeyi anlamadım.
towry

12
Bu cevap inanılmaz derecede yanıltıcı ve kafa karıştırıcı. Lütfen bunun yerine CMS 'veya Faraz Ahmad'ın cevabına bakınız.
iono

214

JavaScript tek iş parçacıklıdır ve senkronize yürütme modeline sahiptir. Tek iş parçacıklı, bir kerede bir komutun yürütüldüğü anlamına gelir. Senkronize, her seferinde bir tane anlamına gelir, yani kodun görünmesi için bir kod satırı aynı anda yürütülür. Yani JavaScript'te her seferinde bir şey oluyor.

Yürütme Bağlamı

JavaScript motoru, tarayıcıdaki diğer motorlarla etkileşime girer. JavaScript yürütme yığınında altta genel bağlam vardır ve ardından işlevleri çağırdığımızda JavaScript motoru ilgili işlevler için yeni yürütme bağlamları oluşturur. Aranan işlev yürütüldüğünde yürütme içeriği yığından çıkarılır ve bir sonraki yürütme içeriği açılır ve bu şekilde devam eder ...

Örneğin

function abc()
{
   console.log('abc');
}


function xyz()
{
   abc()
   console.log('xyz');
}
var one = 1;
xyz();

Yukarıdaki kodda bir global yürütme bağlamı oluşturulacak ve bu bağlamda var onesaklanacak ve xyz () çağrısı çağrıldığında değeri 1 ... olacak ve yeni bir yürütme bağlamı oluşturulacak ve herhangi bir değişken tanımlamış olsaydık xyz işlevinde bu değişkenler xyz () yürütme bağlamında saklanır. Xyz işlevinde abc () öğesini çağırırız ve sonra abc () yürütme içeriği oluşturulur ve yürütme yığınına konur ... Şimdi abc () işlemi tamamlandığında bağlamı yığından, xyz () bağlamı yığın ve sonra küresel bağlam patlayacak ...

Şimdi asenkron geri aramalar hakkında; eşzamansız, aynı anda birden fazla anlamına gelir.

Tıpkı yürütme yığını gibi, Olay Kuyruğu da vardır . JavaScript motorundaki bir olay hakkında bilgilendirilmek istediğimizde, o olayı dinleyebiliriz ve bu olay kuyruğa yerleştirilir. Örneğin bir Ajax istek olayı veya HTTP istek olayı.

Yukarıdaki kod örneğinde gösterildiği gibi, yürütme yığını boş olduğunda, JavaScript motoru periyodik olarak olay kuyruğuna bakar ve bildirilecek herhangi bir olay olup olmadığını görür. Örneğin kuyrukta bir ajax isteği ve bir HTTP isteği olmak üzere iki olay vardı. Ayrıca, o olay tetikleyicisinde çalıştırılması gereken bir işlev olup olmadığını görmek için bakar ... Böylece JavaScript motoru olay hakkında bilgilendirilir ve o olayda yürütülecek ilgili işlevi bilir ... Böylece JavaScript motoru işleyici işlevi, örnek durumda, örneğin AjaxHandler () çağrılır ve her zaman olduğu gibi bir işlev çağrıldığında yürütme içeriği yürütme bağlamına yerleştirilir ve şimdi işlev yürütme tamamlanır ve olay ajax isteği de olay kuyruğundan kaldırılır ... AjaxHandler () bittiğinde, yürütme yığını boş olur, böylece motor tekrar olay kuyruğuna bakar ve sıradaki HTTP isteğinin olay işleyici işlevini çalıştırır. Olay kuyruğunun yalnızca yürütme yığını boşken işlendiğini hatırlamak önemlidir.

Örneğin, Javascript altyapısı tarafından yürütme yığınını ve olay kuyruğu işlemeyi açıklayan aşağıdaki koda bakın.

function waitfunction() {
    var a = 5000 + new Date().getTime();
    while (new Date() < a){}
    console.log('waitfunction() context will be popped after this line');
}

function clickHandler() {
    console.log('click event handler...');   
}

document.addEventListener('click', clickHandler);


waitfunction(); //a new context for this function is created and placed on the execution stack
console.log('global context will be popped after this line');

Ve

<html>
    <head>

    </head>
    <body>

        <script src="program.js"></script>
    </body>
</html>

Şimdi web sayfasını çalıştırın ve sayfayı tıklayın ve çıktıyı konsolda görün. Çıktı

waitfunction() context will be popped after this line
global context will be emptied after this line
click event handler...

JavaScript motoru kodu çalıştırma bağlamı bölümünde açıklandığı gibi senkronize olarak çalıştırıyor, tarayıcı eşzamansız olarak olayları sıraya koyuyor. Böylece tamamlanması çok uzun süren işlevler olay işlemeyi kesintiye uğratabilir. Bir tarayıcıda olaylar gibi olan şeyler JavaScript tarafından bu şekilde ele alınır, çalıştırılması gereken bir dinleyici varsa, yürütme yığını boş olduğunda motor bunu çalıştırır. Ve olaylar gerçekleştikleri sıraya göre işlenir, bu nedenle asenkron kısım motor dışında neler olduğu, yani motor dışarıdaki olaylar meydana geldiğinde ne yapması gerektiği ile ilgilidir.

Dolayısıyla JavaScript her zaman eşzamanlıdır.


16
Bu cevap çok açık, daha fazla oy almalı.
ranu

7
Kesinlikle Javascript'in asenkron davranışları için okuduğum en iyi açıklama.
Charles Jaimet

1
Yürütme bağlamı ve kuyruğunun güzel açıklaması.
Divyanshu Maithani

1
Tabii ki bu yürütme bağlam yığını hakkında biraz okumanızı gerektirir ve sadece boş ve olay que eklenmesi beni nihayet java script excutionin deterministik olarak anlamak gibi hissettiriyor. Daha da kötüsü, sadece bir okuma sayfası gerektirdiğini hissediyorum, ancak neredeyse hiçbir yerde bulamıyorum. Öyleyse neden kimse söylemiyor? Ya bilmiyorlar ya da ne? Ama bir js öğretici bu olsaydı bana çok zaman kazandırmış olabilir hissediyorum. >: |
marshal craft

2
Mükemmel açıklama!
Julsy

100

JavaScript tek iş parçacıklıdır ve normal bir eşzamanlı kod akışı yürütmesinde her zaman çalışırsınız.

JavaScript'in sahip olabileceği eşzamansız davranışın iyi örnekleri, etkinlikler (kullanıcı etkileşimi, Ajax istek sonuçları vb.) Ve zamanlayıcılardır, temelde herhangi bir zamanda gerçekleşebilecek eylemlerdir.

Aşağıdaki makaleye göz atmanızı tavsiye ederim:

Bu makale, JavaScript'in tek iş parçacıklı yapısını ve zamanlayıcıların dahili olarak nasıl çalıştığını ve eşzamansız JavaScript yürütmenin nasıl çalıştığını anlamanıza yardımcı olacaktır.

zaman uyumsuz


Kabul edilen cevap yanlış yönlendirmeleri bu durumda bir şeyler yapabilir miyiz? /
Suraj Jain

8

JS'nin bu sorunun nasıl çalıştığını gerçekten anlayan biri için görünebilir, ancak JS kullanan çoğu insanın bu kadar derin bir kavrayışa sahip olmadığı (ve mutlaka buna ihtiyaç duymadığı) ve onlara oldukça kafa karıştırıcı bir nokta olacak, bu açıdan cevap vermeye çalışın.

JS, kodunun yürütülme biçimiyle eşzamanlıdır. her hat sadece tamamlanmadan önce satırdan sonra çalışır ve bu satır tamamlandıktan sonra bir işlevi çağırırsa vb.

Ana karışıklık noktası, tarayıcınızın JS'ye her zaman daha fazla kod çıkarmasını söyleyebilmesinden kaynaklanmaktadır (bir sayfadaki daha fazla JS kodunu konsoldan nasıl çıkarabileceğinize benzer). Örnek olarak JS'nin amacı JS'nin eşzamansız olarak BEHAVE'e izin vermesini sağlamaktır. Böylece GETbir yanıtın geri dönmesi için yürütülen bir JS işlevini (IE çağrısı) beklerken JS'nin diğer bölümleri çalışabilir. tarayıcının o noktada bir yanıt vardır, olay döngüsü (tarayıcı) geri arama işlevini çağıran JS kodunu yürütür.

Olay döngüsü (tarayıcı) herhangi bir noktada yürütülecek daha fazla JS girebildiğinden, JS eşzamansızdır (bir tarayıcının JS kodunu girmesine neden olacak temel şeyler zaman aşımı, geri arama ve olaydır)

Umarım bu birine yardımcı olacak kadar açıktır.


4

Tanım

"Eşzamansız" terimi, biraz farklı anlamlarda kullanılabilir ve aslında burada olmasa da, görünüşte çelişkili cevaplara neden olur. Asynchrony'deki Wikipedia bu tanıma sahiptir:

Asenkron, bilgisayar programlamasında, ana program akışından bağımsız olayların meydana gelmesini ve bu olaylarla başa çıkma yollarını ifade eder. Bunlar, sinyallerin gelişi gibi "dış" olaylar veya programın sonuçları ile beklemek için engellemeden program yürütme ile eşzamanlı olarak gerçekleştirilen bir program tarafından başlatılan eylemler olabilir.

JavaScript olmayan kod, bu tür "dış" etkinlikleri JavaScript'in bazı etkinlik kuyruklarına sıralayabilir. Ama bu kadarıyla gidiyor.

Önleme Yok

Komut dosyanızda başka bir JavaScript kodu çalıştırmak için JavaScript kodunu çalıştırmanın harici bir kesintisi yoktur . JavaScript parçaları birbiri ardına yürütülür ve sıra, her olay kuyruğundaki olayların sırasına ve bu sıraların önceliğine göre belirlenir.

Örneğin, aşağıdaki kod parçası yürütülürken başka hiçbir JavaScript'in (aynı komut dosyasında) yürütülmeyeceğinden kesinlikle emin olabilirsiniz:

let a = [1, 4, 15, 7, 2];
let sum = 0;
for (let i = 0; i < a.length; i++) {
    sum += a[i];
}

Başka bir deyişle, JavaScript'te herhangi bir önleme yoktur . Olay kuyruklarında ne olursa olsun, bu olayların işlenmesi, bu tür bir kod tamamlanıncaya kadar beklemek zorunda kalacaktır. EcmaScript spesifikasyonu 8.4 İşler ve İşler Kuyrukları bölümünde söylüyor :

Bir İşin yürütülmesi, yalnızca çalışan yürütme bağlamı olmadığında ve yürütme bağlamı yığını boş olduğunda başlatılabilir.

Asenkronize Örnekler

Diğerlerinin zaten yazdığı gibi, JavaScript'te eşzamansızlığın oynatıldığı birkaç durum vardır ve her zaman yalnızca başka bir JavaScript kodu yürütülmediğinde JavaScript yürütülmesine neden olabilecek bir olay kuyruğu içerir:

  • setTimeout(): aracı (örn. tarayıcı) zaman aşımı süresi dolduğunda bir olay kuyruğuna bir olay koyacaktır. Zamanın izlenmesi ve olayın kuyruğa yerleştirilmesi, JavaScript olmayan bir kodla gerçekleşir ve bu nedenle, bunun bazı JavaScript kodlarının yürütülmesine paralel olduğunu hayal edebilirsiniz. Ancak, sağlanan geri arama setTimeoutyalnızca şu anda yürütülen JavaScript kodu tamamlandığında ve uygun olay kuyruğu okunduğunda yürütülebilir.

  • fetch(): aracı, bir HTTP isteği gerçekleştirmek ve gelen yanıtları izlemek için OS işlevlerini kullanır. Yine bu JavaScript dışı görev, halen yürütülmekte olan bazı JavaScript kodlarıyla paralel olarak çalışabilir. Ancak, iade edilen sözü çözecek olan vaat çözüm prosedürü, fetch()yalnızca şu anda yürütülen JavaScript tamamlanınca çalıştırılabilir.

  • requestAnimationFrame(): bir boyama işlemi gerçekleştirmeye hazır olduğunda tarayıcının oluşturma motoru (JavaScript olmayan) JavaScript kuyruğuna bir etkinlik yerleştirir. JavaScript olayı işlendiğinde geri arama işlevi yürütülür.

  • queueMicrotask(): hemen mikro görev kuyruğuna bir olay yerleştirir. Geri arama, çağrı yığını boş olduğunda ve o olay tüketildiğinde yürütülür.

Daha birçok örnek var, ancak tüm bu işlevler ana EcmaScript tarafından değil, ana bilgisayar ortamı tarafından sağlanır. Temel EcmaScript ile, bir etkinliği Promise İş Kuyruğuna eşzamanlı olarak yerleştirebilirsiniz Promise.resolve().

Dil Yapıları

ECMAscript gibi asenkroni desen desteklemek için çeşitli dil yapıları sağlar yield, async, await. Ancak hata olmamasına izin verin: JavaScript kodu harici bir etkinlik tarafından kesilmez . Sağlanan yieldve awaitsağladığı gibi görünen "kesinti", bir işlev çağrısından geri dönmenin ve daha sonra JS koduyla (durumunda yield) veya olay kuyruğuyla ( await).

DOM olay işleme

JavaScript kodu DOM API'sine eriştiğinde, bu bazı durumlarda DOM API'sının bir veya daha fazla senkronize bildirimi tetiklemesine neden olabilir. Kodunuzda bunu dinleyen bir olay işleyicisi varsa çağrılır.

Bu, önleyici eşzamanlılık olarak karşımıza çıkabilir, ancak değildir: olay işleyicileriniz geri döndüğünde, DOM API sonunda geri döner ve orijinal JavaScript kodu devam eder.

Diğer durumlarda DOM API, uygun olay kuyruğunda bir olay gönderir ve çağrı yığını boşaltıldığında JavaScript olayı alır.

Bkz senkron ve asenkron olaylar


0

Tüm durumlarda eşzamanlıdır.

Şununla engelleme dişi örneği Promises:

  const test = () => new Promise((result, reject) => {
    const time = new Date().getTime() + (3 * 1000);

    console.info('Test start...');

    while (new Date().getTime() < time) {
      // Waiting...
    }

    console.info('Test finish...');
  });

  test()
    .then(() => console.info('Then'))
    .finally(() => console.info('Finally'));

  console.info('Finish!');

Çıktı şöyle olacaktır:

Test start...
Test finish...
Finish!

0

"JavaScript'in her zaman eşzamansız olduğu izlenimi edindim"

JavaScript'i senkronize veya senkronize olmayan bir şekilde kullanabilirsiniz. Aslında JavaScript gerçekten iyi bir asenkron desteğe sahiptir. Örneğin, bir veritabanı isteği gerektiren bir kod olabilir. Daha sonra dependentbu isteğin yerine başka bir kod çalıştırabilir , bu isteğin tamamlanmasını beklerken. Bu eşzamansız kodlama, vaatler, eşzamansız / beklemede vb.

'Asenkron' ile ne demek istiyoruz. Bu çok iş parçacıklı anlamına gelmez, aksine bağımlı olmayan bir ilişkiyi tanımlar. Bu popüler yanıttan bu resme göz atın :

         A-Start ------------------------------------------ A-End   
           | B-Start -----------------------------------------|--- B-End   
           |    |      C-Start ------------------- C-End      |      |   
           |    |       |                           |         |      |
           V    V       V                           V         V      V      
1 thread->|<-A-|<--B---|<-C-|-A-|-C-|--A--|-B-|--C-->|---A---->|--B-->| 

Tek iş parçacıklı bir uygulamanın zaman uyumsuz davranış içerebileceğini görüyoruz. A işlevindeki çalışma B işlevinin tamamlanmasına bağlı değildir ve bu nedenle A işlevi B işlevinden önce başlarken, A işlevi daha sonra ve aynı iş parçacığında tamamlanabilir.

Dolayısıyla, JavaScript tek seferde tek bir iş parçacığında bir komut çalıştırdığı için, JavaScript'in yalnızca eşzamanlı bir dil olarak kullanılabileceğini izlemez.

"Ne zaman senkronize olacağı ve ne zaman eşzamansız olacağı konusunda iyi bir referans var mı?"

Sorunuzun kalbi olup olmadığını merak ediyorum. İşte bir cevap:

Bir işlevin zaman uyumsuz olup olmadığını nasıl anlarım?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.