Bir fonksiyonun içinde değiştirdikten sonra değişkenim neden değiştirilmiyor? - Eşzamansız kod referansı


738

Aşağıdaki örnekler göz önüne alındığında, neden outerScopeVarher durumda tanımsızdır?

var outerScopeVar;

var img = document.createElement('img');
img.onload = function() {
    outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);

var outerScopeVar;
setTimeout(function() {
    outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);

// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
});
alert(outerScopeVar);

// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
    outerScopeVar = data;
});
console.log(outerScopeVar);

// with promises
var outerScopeVar;
myPromise.then(function (response) {
    outerScopeVar = response;
});
console.log(outerScopeVar);

// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
    outerScopeVar = pos;
});
console.log(outerScopeVar);

undefinedBu örneklerin hepsinde neden çıktı ? Geçici çözümler istemiyorum, bunun neden olduğunu bilmek istiyorum .


Not: Bu, JavaScript eşzamansızlığı için standart bir sorudur . Bu soruyu geliştirmekten ve topluluğun tanımlayabileceği daha basit örnekler eklemekten çekinmeyin.



@ Teşekkürler teşekkürler, bu linke yorum yaptığımdan eminim ama görünüşe göre bazı eksik yorumlar var. Ayrıca, düzenlemenizle ilgili olarak: Başlıkta "kanonik" ve "eşzamansızlık" bulunmasının, başka bir soruyu bir dupe olarak işaretlemek için bu soruyu ararken yardımcı olduğuna inanıyorum. Ve elbette, eşzamansızlık açıklamalarını ararken Google'dan bu soruyu bulmaya da yardımcı olur.
Fabrício Matté

5
Biraz daha fazla düşünürsek, "kanonik asenkroniklik konusu" başlığında biraz ağır, "asenkron kod referansı" daha basit ve daha objektiftir. Ayrıca çoğu insanın "eşzamansızlık" yerine "eşzamansız" aradığına inanıyorum.
Fabrício Matté

2
Bazı insanlar işlev çağrısından önce değişkenlerini başlatırlar. Bunu bir şekilde temsil eden başlığı değiştirmeye ne dersiniz? "Değişkenim neden bir işlev içinde değiştirildikten sonra değiştirilmiyor?" ?
Felix Kling

Yukarıda bahsettiğiniz tüm kod örneklerinde, "alert (outerScopeVar);" ŞİMDİ yürütür, oysa "outerScopeVar" a değer ataması DAHA SONRA (eşzamansız olarak) gerçekleşir.
refactor

Yanıtlar:


581

Tek kelimeyle cevap: asenkroniklik .

Önsözler

Bu konu, Stack Overflow'da burada en az binlerce kez tekrarlandı. Bu nedenle, ilk önce bazı son derece yararlı kaynaklara dikkat çekmek istiyorum:


Eldeki sorunun cevabı

Önce ortak davranışı izleyelim. Tüm örneklerde, outerScopeVarbir işlev içinde değiştirilir . Bu işlev hemen yürütülmez, bağımsız değişken olarak atanır veya iletilir. Biz buna geri arama diyoruz .

Şimdi soru şu, bu geri arama ne zaman çağrılıyor?

Bu duruma bağlıdır. Ortak davranışları tekrar izlemeye çalışalım:

  • img.onloadgörüntünün başarılı bir şekilde yüklendiği (ve yüklendiği durumlarda) gelecekte bir zamanda çağrılabilir .
  • setTimeoutgecikme süresi dolduktan ve zaman aşımı tarafından iptal edilmedikten sonra gelecekte bir zamanda çağrılabilir clearTimeout. Not: 0gecikme olarak kullanıldığında bile , tüm tarayıcıların minimum zaman aşımı gecikme sınırı vardır (HTML5 spesifikasyonunda 4 ms olarak belirtilir).
  • jQuery'nin $.postgeri çağrısı , Ajax isteği başarıyla tamamlandığında (ve yapıldığında) gelecekte bir zamanda çağrılabilir .
  • Düğüm.js , gelecekte dosya başarıyla okunduğunda veya bir hata atıldığında gelecektefs.readFile çağrılabilir .

Her durumda, ileride çalışabilecek bir geri çağrımız var . Bu "gelecekte bir zaman" asenkron akış olarak adlandırdığımız şeydir .

Asenkron yürütme, senkron akışın dışına itilir. Yani, eşzamansız kod yığını yürütülürken eşzamansız kod hiçbir zaman yürütülmez. JavaScript'in tek iş parçacıklı olmasının anlamı budur.

Daha spesifik olarak, JS motoru boştayken - (a) senkron kod yığınını yürütmüyorsa - zaman uyumsuz geri çağrıları tetikleyebilecek olaylar (örneğin, süresi dolmuş zaman aşımı, ağ yanıtı aldı) ve bunları birbiri ardına yürütür. Bu Olay Döngüsü olarak kabul edilir .

Yani, elle çizilmiş kırmızı şekillerde vurgulanan eşzamansız kod, yalnızca ilgili kod bloklarında kalan tüm eşzamanlı kod yürütüldükten sonra yürütülebilir:

zaman uyumsuz kod vurgulanır

Kısacası, geri arama işlevleri eşzamanlı olarak oluşturulur, ancak eşzamansız olarak yürütülür. Yürütüldüğünü ve nasıl yapılacağını bilmeden eşzamansız bir işlevin yürütülmesine güvenemezsiniz?

Gerçekten basit. Eşzamansız işlev yürütmesine bağlı olan mantık, bu eşzamansız işlevin içinden başlatılmalı / çağrılmalıdır. Örneğin, alerts ve console.logs tuşlarını geri arama işlevinin içine taşımak, sonuç bu noktada mevcut olduğundan beklenen sonucu verir.

Kendi geri arama mantığınızı uygulama

Genellikle, eşzamansız bir işlevin sonucuyla daha fazla şey yapmanız veya eşzamansız işlevin nereden çağrıldığına bağlı olarak sonuçla farklı şeyler yapmanız gerekir. Biraz daha karmaşık bir örneği ele alalım:

var outerScopeVar;
helloCatAsync();
alert(outerScopeVar);

function helloCatAsync() {
    setTimeout(function() {
        outerScopeVar = 'Nya';
    }, Math.random() * 2000);
}

Not: Ben kullanıyorum setTimeoutgenel asenkron fonksiyonu olarak rastgele bir gecikme ile, aynı örnek Ajax için geçerlidir readFile, onloadve diğer asenkron akışı.

Bu örnek açıkça diğer örneklerle aynı sorundan muzdariptir, eşzamansız işlev yürütülene kadar beklemez.

Kendi geri arama sistemimizi uygulayalım. Öncelikle, outerScopeVarbu durumda tamamen işe yaramaz olan çirkinden kurtuluyoruz . Sonra geri çağrımız olan bir işlev bağımsız değişkenini kabul eden bir parametre ekliyoruz. Eşzamansız işlem bittiğinde, bu geri çağrıyı sonucu geçen olarak adlandırırız. Uygulama (lütfen sırayla yorumları okuyun):

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Yukarıdaki örneğin kod snippet'i:

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
console.log("1. function called...")
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    console.log("5. result is: ", result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    console.log("2. callback here is the function passed as argument above...")
    // 3. Start async operation:
    setTimeout(function() {
    console.log("3. start async operation...")
    console.log("4. finished async operation, calling the callback, passing the result...")
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Çoğu zaman gerçek kullanım durumlarında, DOM API ve çoğu kitaplık zaten geri arama işlevselliğini sağlar ( helloCatAsyncbu örnekte uygulama). Yalnızca geri çağrı işlevini geçmeniz ve senkron akıştan yürütüldüğünü anlamanız ve kodunuzu buna göre yeniden yapılandırmanız gerekir.

Ayrıca, eşzamansız returnkod zaten yürütme işlemi bittikten çok sonra yürütüldüğünden , eşzamansız doğa nedeniyle, eşzamansız akıştan geri çağrının tanımlandığı eşzamanlı akışa geri dönüşü olmayan bir değere geri döndürülmesinin imkansız olduğunu göreceksiniz .

Yerine returnuyumsuz bir geri çağırma arasında bir değer ing, sen ... Promises geri arama desen yararlanmak varsa, ya da olacaktır.

sözler

Vanilla JS ile geri çağırma cehennemini korumanın yolları olsa da , vaatler popülerlik kazanıyor ve şu anda ES6'da standartlaştırılıyor (bkz. Promise - MDN ).

Vaatler (diğer adıyla Futures) asenkron kodun daha doğrusal ve dolayısıyla hoş bir okumasını sağlar, ancak tüm işlevlerini açıklamak bu sorunun kapsamı dışındadır. Bunun yerine, bu mükemmel kaynakları ilgilenenler için bırakacağım:


JavaScript eşzamansızlığı hakkında daha fazla okuma materyali

  • Art of Node - Callbacks , vanilla JS örnekleri ve Node.js koduyla eşzamansız kodu ve geri çağrıları çok iyi açıklar.

Not: Bu yanıtı Topluluk Wiki olarak işaretledim, bu nedenle en az 100 itibara sahip olan herkes düzenleyebilir ve geliştirebilir! Lütfen bu yanıtı geliştirmekten çekinmeyin veya isterseniz yeni bir yanıt gönderin.

Ajax ile ilgisiz olan asenkroniklik sorunlarını cevaplamak için bu soruyu kanonik bir konuya dönüştürmek istiyorum (bunun için bir AJAX çağrısından yanıt nasıl geri gönderilir? ), Bu nedenle bu konunun mümkün olduğunca iyi ve yardımcı olması için yardımınıza ihtiyacı var !


1
Son örneğinizde, anonim işlevleri kullanmanızın belirli bir nedeni var mı veya adlandırılmış işlevleri kullanarak aynı şekilde mi çalışacak?
JDelage

1
Kod örnekleri, işlevi çağırdıktan sonra bildirdiğiniz için biraz gariptir. Kaldırma nedeniyle elbette çalışıyor, ama kasıtlı mıydı?
Bergi

2
çıkmaz mı. felix kling cevabınıza işaret ediyor ve felix cevabına işaret ediyorsunuz
Mahi

1
Kırmızı daire kodunun yalnızca zaman uyumsuz olduğunu anlamalısınız çünkü NATIVE zaman uyumsuz javascript işlevleri tarafından yürütülmektedir. Javascript motorunuzun bir özelliği - Node.js veya tarayıcı olsun. Bu aslında bir kara kutu (C vb .. uygulanan) bir işleve "geri arama" olarak geçirildiği için zaman uyumsuzdur. Kazasız geliştiriciye async ... çünkü. Kendi zaman uyumsuz işlevinizi yazmak istiyorsanız, SetTimeout'a (myfunc, 0) göndererek kesmek zorundasınız. Bunu yapmalı mısın? Başka bir tartışma .... muhtemelen hayır.
Sean Anderson

@Fabricio Ben "> = 4ms kelepçe" tanımlayan spec aradım, ama bulamadım - MDN üzerinde benzer mekanizma (iç içe çağrıları kelepçe için) bazı söz bulundu - developer.mozilla.org/en-US/docs / Web / API /… - HTML spesifikasyonunun sağ kısmına bağlantı veren var mı?
Sebi

156

Fabrício'nun cevabı yerinde; ama cevabını asenkroniklik kavramını açıklamaya yardımcı olacak bir benzetmeye odaklanan daha az teknik bir şeyle tamamlamak istedim .


Bir Analoji ...

Dün yaptığım iş bir meslektaşımdan bazı bilgiler gerektiriyordu. Onu çaldım; konuşma böyle gitti:

Beni : Merhaba Bob, nasıl bilmek gerekir foo 'd çubuğu ' geçen hafta d. Jim bu konuda bir rapor istiyor ve bununla ilgili ayrıntıları bilen tek kişi sensin.

Bob : Elbette, ama 30 dakika sürecek mi?

Ben : Bu harika Bob. Bilgiyi aldığınızda bana geri dönün!

Bu noktada telefonu kapattım. Raporumu tamamlamak için Bob'dan bilgiye ihtiyacım olduğundan, raporu bıraktım ve onun yerine bir kahve içmeye gittim, sonra bir e-posta aldım. 40 dakika sonra (Bob yavaş), Bob aradı ve bana ihtiyacım olan bilgiyi verdi. Bu noktada, ihtiyacım olan tüm bilgilere sahip olduğum için raporumla çalışmaya devam ettim.


Konuşmanın bunun yerine geçip gitmediğini düşünün;

Beni : Merhaba Bob, nasıl bilmek gerekir foo 'd çubuğu ' geçen hafta d. Jim bununla ilgili bir rapor istiyor ve bununla ilgili ayrıntıları bilen tek kişi sensin.

Bob : Elbette, ama 30 dakika sürecek mi?

Ben : Bu harika Bob. Bekleyeceğim.

Orada oturdum ve bekledim. Ve bekledi. Ve bekledi. 40 dakika boyunca. Beklemek dışında hiçbir şey yapmamak. Sonunda Bob bana bilgi verdi, telefonu kapattık ve raporumu tamamladım. Ama 40 dakikalık üretkenlik kaybettim.


Bu, eşzamansız ve eşzamanlı davranıştır

Sorumumuzdaki tüm örneklerde olan tam olarak budur. Bir görüntüyü yüklemek, bir dosyayı diskten yüklemek ve AJAX aracılığıyla bir sayfa istemek yavaş işlemlerdir (modern bilgi işlem bağlamında).

JavaScript, bu yavaş işlemlerin tamamlanmasını beklemek yerine, yavaş işlem tamamlandığında yürütülecek bir geri arama işlevi kaydetmenizi sağlar. Ancak bu arada, JavaScript başka bir kod yürütmeye devam edecektir. Yavaş işlemin tamamlanmasını beklerken JavaScript'in diğer kodu yürütmesi davranışı eşzamansız hale getirir . JavaScript, başka bir kod çalıştırmadan önce işlemin tamamlanmasını bekleseydi, bu eşzamanlı davranış olurdu .

var outerScopeVar;    
var img = document.createElement('img');

// Here we register the callback function.
img.onload = function() {
    // Code within this function will be executed once the image has loaded.
    outerScopeVar = this.width;
};

// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);

Yukarıdaki kodda lolcat.png, bir sloooow işlemi olan JavaScript'in yüklenmesini istiyoruz . Bu yavaş işlem yapıldıktan sonra geri çağrı işlevi yürütülür, ancak bu arada JavaScript sonraki kod satırlarını işlemeye devam eder; yani alert(outerScopeVar).

Bu yüzden uyarının gösterildiğini görüyoruz undefined; çünkü alert()görüntü yüklendikten sonra hemen işlenir.

Bizim kodunu çözmek için, yapmamız gereken tüm taşımaktır alert(outerScopeVar)kod içine geri arama işlevi. Bunun bir sonucu olarak, artık outerScopeVarküresel bir değişken olarak bildirilen değişkene ihtiyacımız yok .

var img = document.createElement('img');

img.onload = function() {
    var localScopeVar = this.width;
    alert(localScopeVar);
};

img.src = 'lolcat.png';

Her zaman bir geri aramanın işlev olarak belirtildiğini görürsünüz, çünkü JavaScript'te bazı kodları tanımlamanın tek * yolu budur, ancak daha sonraya kadar yürütülmez.

Bu nedenle, tüm örneklerimizde function() { /* Do something */ }geri arama; tüm örnekleri düzeltmek için tek yapmamız gereken, işlemin yanıtını gerektiren kodu oraya taşımaktır!

* Teknik eval()olarak da kullanabilirsiniz , ancak bu amaç için eval()kötüdür


Arayanı nasıl bekletirim?

Şu anda buna benzer bir kodunuz olabilir;

function getWidthOfImage(src) {
    var outerScopeVar;

    var img = document.createElement('img');
    img.onload = function() {
        outerScopeVar = this.width;
    };
    img.src = src;
    return outerScopeVar;
}

var width = getWidthOfImage('lolcat.png');
alert(width);

Ancak, artık bunun return outerScopeVarhemen gerçekleştiğini biliyoruz ; onloadGeri arama işlevi değişkeni güncellemeden önce . Bu getWidthOfImage()geri dönmeye undefinedve undefineduyarılmaya yol açar .

Bunu düzeltmek için, çağıran fonksiyonun getWidthOfImage()bir geri arama kaydetmesine izin vermeliyiz, ardından genişliğin uyarısını o geri arama içinde olacak şekilde taşımalıyız;

function getWidthOfImage(src, cb) {     
    var img = document.createElement('img');
    img.onload = function() {
        cb(this.width);
    };
    img.src = src;
}

getWidthOfImage('lolcat.png', function (width) {
    alert(width);
});

... daha önce olduğu gibi, global değişkenleri kaldırabildiğimizi unutmayın (bu örnekte width).


4
Ancak sonuçları farklı bir hesaplamada kullanmak veya bir nesne değişkeninde saklamak istiyorsanız, konsola uyarı vermek veya konsola göndermek nasıl yararlı olur?
Ken Ingram

73

İşte hızlı bir referans arayan insanlar için daha özlü bir yanıtın yanı sıra vaatler ve async / bekliyor kullanan bazı örnekler.

Eşzamansız bir yöntemi çağıran (bu durumda setTimeout) bir işlev için naif yaklaşımla (işe yaramaz) başlayın : bir mesaj döndürür:

function getMessage() {
  var outerScopeVar;
  setTimeout(function() {
    outerScopeVar = 'Hello asynchronous world!';
  }, 0);
  return outerScopeVar;
}
console.log(getMessage());

undefinedgeri arama çağrılmadan getMessageönce döner setTimeoutve güncellenir çünkü bu durumda oturum açılır outerScopeVar.

Bunu çözmenin iki ana yolu geri aramalar ve vaatler kullanmaktır :

Callbacks

Buradaki değişiklik , sonuçları uygun olduğunda arama koduna geri göndermek için çağrılacak getMessagebir callbackparametreyi kabul etmesidir .

function getMessage(callback) {
  setTimeout(function() {
    callback('Hello asynchronous world!');
  }, 0);
}
getMessage(function(message) {
  console.log(message);
});

sözler

Vaatler, birden fazla zaman uyumsuz işlemi koordine etmek için doğal olarak birleştirilebildiğinden, geri çağrılardan daha esnek bir alternatif sunar. Bir Promises / A + standart uygulaması, node.js (0.12+) ve birçok geçerli tarayıcıda yerel olarak sağlanır, ancak Bluebird ve Q gibi kitaplıklarda da uygulanır .

function getMessage() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('Hello asynchronous world!');
    }, 0);
  });
}

getMessage().then(function(message) {
  console.log(message);  
});

jQuery Ertelenmiş

jQuery, Deferreds ile vaatlerine benzer bir işlevsellik sağlar.

function getMessage() {
  var deferred = $.Deferred();
  setTimeout(function() {
    deferred.resolve('Hello asynchronous world!');
  }, 0);
  return deferred.promise();
}

getMessage().done(function(message) {
  console.log(message);  
});

zaman uyumsuz / bekliyoruz

JavaScript ortamınız asyncve await(Node.js 7.6+ gibi) için destek içeriyorsa , vaatleri asyncişlevler arasında eşzamanlı olarak kullanabilirsiniz :

function getMessage () {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('Hello asynchronous world!');
        }, 0);
    });
}

async function main() {
    let message = await getMessage();
    console.log(message);
}

main();

Promises hakkındaki örneğiniz temelde son birkaç saattir aradığım şey. Örneğiniz güzel ve sözleri aynı anda açıklıyor. Neden bu başka bir yerde değil boggling.
Vincent P

Bu iyi, ama parametreleri ile getMessage () çağırmanız gerekiyorsa? Bu senaryoda yukarıdakileri nasıl yazardınız?
Chiwda

2
@Chiwda Sadece son parametre geri arama koydu: function getMessage(param1, param2, callback) {...}.
JohnnyHK

async/awaitÖrneğini deniyorum ama problemlerle karşılaşıyorum. Bir somutlaştırmak yerine, new Promisebir .Get()çağrı yapıyorum ve bu nedenle herhangi bir resolve()yönteme erişemiyorum . Böylece benimgetMessage() sonucumu değil Sözümü geri . Bunun için çalışan bir sözdizimi göstermek üzere cevabınızı biraz düzenleyebilir misiniz?
InteXX

@InteXX Ne yapmak istediğinizden emin değilim .Get() Arama . Muhtemelen yeni bir soru göndermek en iyisidir.
JohnnyHK

56

Bariz olanı belirtmek için kupa temsil eder outerScopeVar.

Asenkron fonksiyonlar ...

eşzamansız kahve çağrısı


14
Senkronize olmayan bir işlevi eşzamanlı olarak hareket ettirmeye çalışmak, kahveyi 1 saniyede içmeye ve 1 dakika içinde kucağınıza dökülmeye çalışacaktır.
Teepeemm

Eğer bariz olanı belirtiyor olsaydı, sorunun sorulacağını sanmıyorum, değil mi?
broccoli2000

2
@ broccoli2000 Bu yüzden sorunun açık olduğu anlamına gelmiyordum, ancak kupanın çizimde neyi temsil ettiği açıktı :)
Johannes Fahrenkrug

14

Diğer cevaplar mükemmel ve bu konuya doğrudan bir cevap vermek istiyorum. Sadece jQuery asenkron çağrılarıyla sınırlanıyor

Tüm ajax çağrıları ( $.getveya $.postveya dahil $.ajax) eşzamansızdır.

Örneğiniz düşünüldüğünde

var outerScopeVar;  //line 1
$.post('loldog', function(response) {  //line 2
    outerScopeVar = response;
});
alert(outerScopeVar);  //line 3

Kod yürütme 1. satırdan başlar, değişken ve tetikleyicileri ve 2. satırdaki asenkron çağrıyı (yani, post isteği) bildirir ve post isteğinin yürütülmesini beklemeden 3. satırdan yürütülmesine devam eder.

Diyelim ki gönderi isteğinin tamamlanması 10 saniye sürüyor, değeri outerScopeVaryalnızca bu 10 saniyeden sonra ayarlanacak.

Denemek için,

var outerScopeVar; //line 1
$.post('loldog', function(response) {  //line 2, takes 10 seconds to complete
    outerScopeVar = response;
});
alert("Lets wait for some time here! Waiting is fun");  //line 3
alert(outerScopeVar);  //line 4

Şimdi bunu çalıştırdığınızda, 3. satırda bir uyarı alırsınız. Şimdi, gönderme isteğinin bir değer döndürdüğünden emin olana kadar bir süre bekleyin. Sonra Tamam'ı tıklattığınızda, uyarı kutusunda, bir sonraki uyarı beklenen değeri yazdıracaktır, çünkü siz beklediniz.

Gerçek hayat senaryosunda kod,

var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
    alert(outerScopeVar);
});

Eşzamansız çağrılara bağlı olan tüm kod, eşzamansız bloğun içine veya eşzamansız çağrıları bekleyerek taşınır.


or by waiting on the asynchronous callsbiri bunu nasıl yapar?
InteXX

@InteXX Geri arama yöntemi kullanarak
Teja

Hızlı bir sözdizimi örneğiniz var mı?
InteXX

11

Tüm bu senaryolarda outerScopeVar, geçerli yürütmenin beklemeyeceği eşzamansız olarak veya daha sonra gerçekleşen (bir olayın gerçekleşmesini beklemek veya dinlemek) bir değer değiştirilir veya atanır .outerScopeVar = undefined

Her bir örneği tartışalım (bazı olayların gerçekleşmesi için eşzamansız olarak adlandırılan veya geciktirilen kısmı işaretledim):

1.

resim açıklamasını buraya girin

Burada belirli bir olay üzerine yürütülecek bir olay listesini kaydederiz.Görüntünün yüklenmesi.O zaman geçerli yürütme sonraki satırlarla devam eder img.src = 'lolcat.png';ve alert(outerScopeVar);bu arada olay meydana gelmeyebilir. yani işlev img.onload, atıfta bulunulan görüntünün eşzamansız olarak yüklenmesini bekler. Bu, aşağıdaki tüm örnek olacak - olay farklı olabilir.

2.

2

Burada zaman aşımı olayı, belirtilen süreden sonra işleyiciyi çağıracak rolü oynar. İşte 0, ama yine de Event Queue, yürütme için son konumuna eklenecek olan asenkron bir olayı kaydeder , bu da garantili gecikmeyi yapar.

3.

resim açıklamasını buraya girin Bu kez ajax geri arama.

4.

resim açıklamasını buraya girin

Düğüm, eşzamansız kodlamanın kralı olarak düşünülebilir.İşaretlenen işlev, belirtilen dosyayı okuduktan sonra yürütülecek bir geri arama işleyicisi olarak kaydedilir.

5.

resim açıklamasını buraya girin

Açık söz (gelecekte bir şeyler yapılacaktır) eşzamansızdır. bkz JavaScript Ertelenmiş, Promise ve Geleceğe arasındaki farklar nelerdir?

https://www.quora.com/Whats-the-difference-between-a-promise-and-a-callback-in-Javascript

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.