Mengapa variabel saya tidak berubah setelah saya memodifikasinya di dalam suatu fungsi? - Referensi kode tidak sinkron


738

Dengan contoh-contoh berikut, mengapa tidak outerScopeVarterdefinisi dalam semua kasus?

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);

Mengapa hasilnya undefineddalam semua contoh ini? Saya tidak ingin penyelesaian, saya ingin tahu mengapa ini terjadi.


Catatan: Ini adalah pertanyaan kanonik untuk JavaScript asynchronicity . Jangan ragu untuk memperbaiki pertanyaan ini dan menambahkan lebih banyak contoh sederhana yang dapat diidentifikasi oleh komunitas.



@Dukeling terima kasih, saya cukup yakin bahwa saya telah berkomentar dengan tautan itu tetapi ternyata ada beberapa komentar yang hilang. Juga, mengenai hasil edit Anda: Saya yakin memiliki "kanonik" dan "asinkronisitas" dalam judul membantu ketika mencari pertanyaan ini untuk menandai pertanyaan lain sebagai dupe. Dan tentu saja, ini juga membantu dalam menemukan pertanyaan ini dari Google ketika mencari penjelasan asinkronisitas.
Fabrício Matté

5
Menempatkan sedikit lebih banyak pemikiran, "topik asynchronicity kanonik" agak berat pada judul, "referensi kode asinkron" lebih sederhana dan lebih objektif. Saya juga percaya kebanyakan orang mencari "asinkron" bukan "asinkronik".
Fabrício Matté

2
Beberapa orang menginisialisasi variabel mereka sebelum pemanggilan fungsi. Bagaimana dengan mengubah judul yang entah bagaimana mewakili hal itu juga? Seperti "Mengapa variabel saya tidak berubah setelah saya memodifikasinya di dalam suatu fungsi?" ?
Felix Kling

Dalam semua contoh kode yang telah Anda sebutkan di atas, "alert (outerScopeVar);" dieksekusi SEKARANG, sedangkan pemberian nilai ke "outerScopeVar" terjadi KEMUDIAN (asinkron).
refactor

Jawaban:


581

Satu kata jawaban: asynchronicity .

Kata pengantar

Topik ini telah diulang setidaknya beberapa ribu kali, di sini, di Stack Overflow. Karenanya, pertama saya ingin menunjukkan beberapa sumber daya yang sangat berguna:


Jawaban atas pertanyaan yang ada

Mari kita telusuri perilaku umum dulu. Dalam semua contoh, outerScopeVardimodifikasi di dalam suatu fungsi . Fungsi itu jelas tidak segera dieksekusi, sedang ditugaskan atau diteruskan sebagai argumen. Itulah yang kami sebut panggilan balik .

Sekarang pertanyaannya adalah, kapan panggilan balik itu dipanggil?

Tergantung kasusnya. Mari kita coba melacak beberapa perilaku umum lagi:

  • img.onloaddapat dipanggil suatu saat nanti , ketika (dan jika) gambar telah berhasil dimuat.
  • setTimeoutdapat dipanggil kapan - kapan di masa depan , setelah penundaan berakhir dan batas waktu belum dibatalkan oleh clearTimeout. Catatan: bahkan ketika menggunakan 0sebagai penundaan, semua browser memiliki batas waktu tunggu batas waktu minimum (ditetapkan menjadi 4ms dalam spesifikasi HTML5).
  • Panggilan $.postbalik jQuery dapat dipanggil kapan saja di masa mendatang , ketika (dan jika) permintaan Ajax telah berhasil diselesaikan.
  • Node.js fs.readFilemungkin dipanggil di masa mendatang , ketika file telah dibaca dengan sukses atau dilempar kesalahan.

Dalam semua kasus, kami memiliki panggilan balik yang dapat berjalan di masa mendatang . "Suatu saat di masa depan" inilah yang kami sebut sebagai aliran asinkron .

Eksekusi asinkron didorong keluar dari aliran sinkron. Yaitu, kode asinkron tidak akan pernah dijalankan ketika tumpukan kode sinkron dijalankan. Ini adalah arti JavaScript menjadi single-threaded.

Lebih khusus lagi, ketika mesin JS idle - tidak mengeksekusi tumpukan (a) kode sinkron - itu akan polling untuk peristiwa yang mungkin telah memicu callback tidak sinkron (misalnya batas waktu habis, respon jaringan yang diterima) dan menjalankannya satu demi satu. Ini dianggap sebagai Perulangan Acara .

Yaitu, kode asinkron yang disorot dalam bentuk merah digambar tangan hanya dapat dijalankan setelah semua kode sinkron yang tersisa di masing-masing blok kode telah dieksekusi:

kode async disorot

Singkatnya, fungsi-fungsi panggilan balik dibuat secara sinkron tetapi dijalankan secara tidak sinkron. Anda tidak bisa mengandalkan eksekusi fungsi asinkron sampai Anda tahu itu telah dieksekusi, dan bagaimana melakukannya?

Sederhana, sungguh. Logika yang bergantung pada eksekusi fungsi asinkron harus dimulai / dipanggil dari dalam fungsi asinkron ini. Misalnya, memindahkan alerts dan console.logs terlalu dalam fungsi panggilan balik akan menampilkan hasil yang diharapkan, karena hasilnya tersedia pada saat itu.

Menerapkan logika panggilan balik Anda sendiri

Seringkali Anda perlu melakukan lebih banyak hal dengan hasil dari fungsi asinkron atau melakukan hal yang berbeda dengan hasil tergantung di mana fungsi asinkron dipanggil. Mari kita bahas contoh yang sedikit lebih rumit:

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

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

Catatan: Saya menggunakan setTimeoutdengan penundaan acak sebagai fungsi asinkron generik, contoh yang sama berlaku untuk Ajax readFile,, onloaddan aliran asinkron lainnya.

Contoh ini jelas menderita dari masalah yang sama seperti contoh lainnya, tidak menunggu sampai fungsi asinkron dijalankan.

Mari kita hadapi itu menerapkan sistem panggilan balik kita sendiri. Pertama, kita menyingkirkan yang jelek outerScopeVaryang sama sekali tidak berguna dalam kasus ini. Kemudian kami menambahkan parameter yang menerima argumen fungsi, panggilan balik kami. Ketika operasi asinkron selesai, kami memanggil panggilan balik ini melewati hasilnya. Implementasinya (harap baca komentar secara berurutan):

// 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);
}

Cuplikan kode dari contoh di atas:

// 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);
}

Paling sering dalam kasus penggunaan nyata, DOM API dan sebagian besar perpustakaan sudah menyediakan fungsi panggilan balik ( helloCatAsyncimplementasi dalam contoh demonstratif ini). Anda hanya perlu melewati fungsi callback dan memahami bahwa itu akan mengeksekusi keluar dari aliran sinkron, dan menyusun kembali kode Anda untuk mengakomodasi itu.

Anda juga akan melihat bahwa karena sifat asinkron, tidak mungkin returnnilai dari aliran asinkron kembali ke aliran sinkron di mana panggilan balik ditentukan, karena panggilan balik asinkron dijalankan lama setelah kode sinkron telah selesai dijalankan.

Alih-alih returnmemasukkan nilai dari callback asinkron, Anda harus menggunakan pola callback, atau ... Janji.

Janji

Meskipun ada cara untuk menjaga panggilan balik dengan vanilla JS, janji semakin populer dan saat ini sedang distandarisasi dalam ES6 (lihat Janji - MDN ).

Promises (alias Futures) memberikan pembacaan kode asinkron yang lebih linier, dan dengan demikian menyenangkan, tetapi menjelaskan seluruh fungsionalitasnya berada di luar cakupan pertanyaan ini. Sebagai gantinya, saya akan meninggalkan sumber daya yang bagus ini untuk yang tertarik:


Lebih banyak bahan bacaan tentang JavaScript asynchronicity

  • Seni Node - Callback menjelaskan kode asinkron dan callback dengan sangat baik dengan contoh vanilla JS dan kode Node.js juga.

Catatan: Saya telah menandai jawaban ini sebagai Wiki Komunitas, karenanya siapa pun dengan setidaknya 100 reputasi dapat mengedit dan memperbaikinya! Silakan meningkatkan jawaban ini, atau kirimkan jawaban yang sama sekali baru jika Anda mau.

Saya ingin mengubah pertanyaan ini menjadi topik kanonik untuk menjawab masalah asinkronisitas yang tidak terkait dengan Ajax (ada Bagaimana mengembalikan respons dari panggilan AJAX? Untuk itu), maka topik ini memerlukan bantuan Anda untuk menjadi sebaik dan membantu mungkin. !


1
Dalam contoh terakhir Anda, apakah ada alasan khusus mengapa Anda menggunakan fungsi anonim atau apakah akan berfungsi sama dengan menggunakan fungsi bernama?
JDelage

1
Contoh kode agak aneh ketika Anda mendeklarasikan fungsi setelah memanggilnya. Berfungsi karena mengangkat tentu saja, tetapi apakah itu disengaja?
Bergi

2
apakah itu jalan buntu. felix kling menunjuk ke jawaban Anda dan Anda menunjuk ke jawaban felix
Mahi

1
Anda perlu memahami bahwa kode lingkaran merah hanya async karena sedang dijalankan oleh fungsi javascript async NATIVE. Ini adalah fitur mesin javascript Anda - apakah itu Node.js atau browser. Itu async karena sedang diteruskan sebagai "panggilan balik" ke fungsi yang pada dasarnya adalah kotak hitam (diimplementasikan dalam C dll.). Bagi pengembang yang malang mereka async ... hanya karena. Jika Anda ingin menulis fungsi async Anda sendiri, Anda harus meretasnya dengan mengirimkannya ke SetTimeout (myfunc, 0). Haruskah kamu melakukan itu? Debat lain .... mungkin tidak.
Sean Anderson

@Fabricio Saya telah mencari spesifikasi yang mendefinisikan "> = 4ms clamp", tetapi tidak dapat menemukannya - Saya menemukan beberapa penyebutan mekanisme serupa (untuk menjepit panggilan bersarang) di MDN - developer.mozilla.org/en-US/docs / Web / API / ... - apakah ada yang punya tautan ke bagian kanan dari spesifikasi HTML.
Sebi

156

Jawaban Fabrício sangat tepat; tetapi saya ingin melengkapi jawabannya dengan sesuatu yang kurang teknis, yang berfokus pada analogi untuk membantu menjelaskan konsep asinkronisitas .


Analogi ...

Kemarin, pekerjaan yang saya lakukan memerlukan beberapa informasi dari seorang kolega. Saya meneleponnya; Beginilah percakapan berlangsung:

Me : Hi Bob, saya perlu tahu bagaimana kita foo 'd bar ' d pekan lalu. Jim ingin laporan tentang itu, dan kaulah satu-satunya yang tahu detail tentang hal itu.

Bob : Tentu saja, tapi itu akan memakan waktu sekitar 30 menit?

Saya : Bob hebat. Berikan saya cincin kembali ketika Anda mendapat informasi!

Pada titik ini, saya menutup telepon. Karena saya memerlukan informasi dari Bob untuk menyelesaikan laporan saya, saya meninggalkan laporan dan pergi untuk minum kopi, kemudian saya menyusul beberapa email. 40 menit kemudian (Bob lambat), Bob menelepon kembali dan memberi saya informasi yang saya butuhkan. Pada titik ini, saya melanjutkan pekerjaan saya dengan laporan saya, karena saya memiliki semua informasi yang saya butuhkan.


Bayangkan jika percakapan sudah seperti ini sebagai gantinya;

Me : Hi Bob, saya perlu tahu bagaimana kita foo 'd bar ' d pekan lalu. Jim ingin melaporkannya, dan kaulah satu-satunya yang tahu detailnya.

Bob : Tentu saja, tapi itu akan memakan waktu sekitar 30 menit?

Saya : Bob hebat. Aku akan menunggu.

Dan saya duduk di sana dan menunggu. Dan menunggu. Dan menunggu. Selama 40 menit. Tidak melakukan apa-apa selain menunggu. Akhirnya, Bob memberi saya informasi, kami menutup telepon, dan saya menyelesaikan laporan saya. Tapi saya kehilangan 40 menit produktivitas.


Ini adalah perilaku asinkron vs sinkron

Inilah yang terjadi dalam semua contoh dalam pertanyaan kami. Memuat gambar, memuat file dari disk, dan meminta halaman melalui AJAX semuanya berjalan lambat (dalam konteks komputasi modern).

Daripada menunggu operasi lambat ini selesai, JavaScript memungkinkan Anda mendaftarkan fungsi panggilan balik yang akan dieksekusi ketika operasi lambat selesai. Sementara itu, JavaScript akan terus mengeksekusi kode lain. Fakta bahwa JavaScript mengeksekusi kode lain sambil menunggu operasi lambat untuk menyelesaikan membuat perilaku tidak sinkron . Seandainya JavaScript menunggu operasi untuk diselesaikan sebelum mengeksekusi kode lain, ini akan menjadi perilaku sinkron .

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);

Pada kode di atas, kami meminta JavaScript untuk memuat lolcat.png, yang merupakan operasi sloooow . Fungsi panggilan balik akan dieksekusi setelah operasi lambat ini selesai, tetapi sementara itu, JavaScript akan terus memproses baris kode berikutnya; yaitu alert(outerScopeVar).

Inilah sebabnya kami melihat lansiran ditampilkan undefined; sejak alert()diproses segera, bukan setelah gambar telah dimuat.

Untuk memperbaiki kode kita, yang harus kita lakukan adalah memindahkan alert(outerScopeVar)kode ke fungsi panggilan balik. Sebagai konsekuensi dari ini, kita tidak perlu lagi outerScopeVarvariabel dideklarasikan sebagai variabel global.

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

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

img.src = 'lolcat.png';

Anda akan selalu melihat panggilan balik ditentukan sebagai fungsi, karena itulah satu-satunya * cara dalam JavaScript untuk mendefinisikan beberapa kode, tetapi tidak menjalankannya sampai nanti.

Karena itu, dalam semua contoh kami, function() { /* Do something */ }ini adalah panggilan baliknya; untuk memperbaiki semua contoh, yang harus kita lakukan adalah memindahkan kode yang memerlukan respons operasi ke sana!

* Secara teknis Anda dapat menggunakan eval()juga, tetapi eval()jahat untuk tujuan ini


Bagaimana cara membuat penelepon saya menunggu?

Saat ini Anda mungkin memiliki beberapa kode yang mirip dengan ini;

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);

Namun, kita sekarang tahu bahwa itu return outerScopeVarterjadi segera; sebelum onloadfungsi callback memperbarui variabel. Ini mengarah ke getWidthOfImage()pengembalian undefined, dan undefineddiperingatkan.

Untuk memperbaikinya, kita perlu mengizinkan fungsi panggilan getWidthOfImage()untuk mendaftarkan panggilan balik, lalu memindahkan peringatan lebar menjadi dalam panggilan balik itu;

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);
});

... seperti sebelumnya, perhatikan bahwa kami dapat menghapus variabel global (dalam hal ini width).


4
Tetapi bagaimana peringatan atau pengiriman ke konsol berguna jika Anda ingin menggunakan hasil dalam perhitungan yang berbeda, atau menyimpannya dalam variabel objek?
Ken Ingram

73

Berikut ini jawaban yang lebih ringkas untuk orang yang mencari referensi cepat serta beberapa contoh menggunakan janji dan asink / tunggu.

Mulai dengan pendekatan naif (yang tidak berfungsi) untuk fungsi yang memanggil metode asinkron (dalam kasus ini setTimeout) dan mengembalikan pesan:

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

undefinedmasuk dalam kasus ini karena getMessagekembali sebelum setTimeoutpanggilan balik dipanggil dan diperbarui outerScopeVar.

Dua cara utama untuk menyelesaikannya adalah menggunakan callback dan janji :

Telepon balik

Perubahan di sini adalah getMessagemenerima callbackparameter yang akan dipanggil untuk mengirimkan hasilnya kembali ke kode panggilan yang pernah tersedia.

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

Janji

Janji memberikan alternatif yang lebih fleksibel daripada callback karena mereka dapat secara alami digabungkan untuk mengoordinasikan beberapa operasi async. Sebuah Janji / A + penerapan standar native disediakan dalam node.js (0.12+) dan banyak browser saat ini, tetapi juga diterapkan di perpustakaan seperti Bluebird dan Q .

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

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

jQuery Deferreds

jQuery menyediakan fungsionalitas yang mirip dengan janji dengan Tangguhannya.

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

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

async / tunggu

Jika lingkungan JavaScript Anda menyertakan dukungan untuk asyncdan await(seperti Node.js 7.6+), maka Anda dapat menggunakan janji secara sinkron dalam asyncfungsi:

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();

Sampel Anda pada Janji pada dasarnya adalah apa yang saya cari, selama beberapa jam terakhir. Teladan Anda indah dan menjelaskan Janji pada saat yang sama. Mengapa ini tidak ada di tempat lain membingungkan.
Vincent P

Ini semua baik-baik saja, tetapi bagaimana jika Anda perlu memanggil getMessage () dengan parameter? Bagaimana Anda menulis di atas dalam skenario itu?
Chiwda

2
@Chiwda Anda hanya menempatkan panggilan balik parameter terakhir: function getMessage(param1, param2, callback) {...}.
JohnnyHK

Saya mencoba async/awaitsampel Anda , tetapi saya mengalami masalah. Alih-alih membuat contoh new Promise, saya membuat .Get()panggilan dan karena itu tidak memiliki akses ke resolve()metode apa pun . Jadi saya getMessage()mengembalikan Janji dan bukan hasilnya. Bisakah Anda mengedit jawaban Anda sedikit untuk menunjukkan sintaks yang berfungsi untuk ini?
InteXX

@InteXX Saya tidak yakin apa maksud Anda melakukan .Get()panggilan. Mungkin yang terbaik untuk mengirim pertanyaan baru.
JohnnyHK

56

Untuk menyatakan yang jelas, cawan mewakili outerScopeVar.

Fungsi asinkron menjadi seperti ...

panggilan asinkron untuk minum kopi


14
Sedangkan mencoba membuat fungsi asinkron bertindak serempak akan mencoba minum kopi pada 1 detik, dan setelah itu dituangkan ke pangkuan Anda pada 1 menit.
Teepeemm

Jika itu menyatakan yang jelas, saya tidak berpikir pertanyaan itu akan ditanyakan, Tidak?
broccoli2000

2
@ broccoli2000 Dengan itu saya tidak bermaksud bahwa pertanyaannya sudah jelas, tetapi bahwa sudah jelas apa yang diwakili oleh cangkir dalam gambar :)
Johannes Fahrenkrug

14

Jawaban lainnya sangat bagus dan saya hanya ingin memberikan jawaban langsung untuk ini. Hanya membatasi untuk panggilan sinkron jQuery jQuery

Semua panggilan ajax (termasuk $.getatau $.postatau $.ajax) tidak sinkron.

Mempertimbangkan contoh Anda

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

Eksekusi kode dimulai dari baris 1, mendeklarasikan variabel dan pemicu serta panggilan tidak sinkron di jalur 2, (yaitu, permintaan pos) dan melanjutkan eksekusi dari baris 3, tanpa menunggu permintaan pos untuk menyelesaikan pelaksanaannya.

Katakanlah bahwa permintaan posting selesai 10 detik, nilai outerScopeVarhanya akan ditetapkan setelah 10 detik itu.

Untuk mencoba,

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

Sekarang ketika Anda menjalankan ini, Anda akan mendapatkan peringatan di jalur 3. Sekarang tunggu beberapa saat sampai Anda yakin permintaan pos telah mengembalikan beberapa nilai. Kemudian ketika Anda mengklik OK, pada kotak peringatan, peringatan berikutnya akan mencetak nilai yang diharapkan, karena Anda menunggu.

Dalam skenario kehidupan nyata, kode tersebut menjadi,

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

Semua kode yang bergantung pada panggilan asinkron, dipindahkan di dalam blok asinkron, atau dengan menunggu panggilan asinkron.


or by waiting on the asynchronous callsBagaimana seseorang melakukan itu?
InteXX

@InteXX Dengan menggunakan metode panggilan balik
Teja

Apakah Anda memiliki contoh sintaks yang cepat?
InteXX

11

Dalam semua skenario outerScopeVarini dimodifikasi atau diberikan nilai secara tidak sinkron atau terjadi di kemudian hari (menunggu atau mendengarkan beberapa peristiwa terjadi), di mana eksekusi saat ini tidak akan menunggu . Jadi semua kasus ini arus eksekusi saat ini menghasilkanouterScopeVar = undefined

Mari kita bahas masing-masing contoh (saya menandai bagian yang disebut tidak sinkron atau tertunda agar beberapa peristiwa terjadi):

1.

masukkan deskripsi gambar di sini

Di sini kita mendaftarkan eventlistner yang akan dieksekusi pada peristiwa tertentu. Di sini memuat gambar. Kemudian eksekusi saat ini berlanjut dengan baris berikutnya img.src = 'lolcat.png';dan alert(outerScopeVar);sementara itu acara mungkin tidak terjadi. yaitu, funtion img.onloadmenunggu gambar yang dimaksud untuk dimuat, tanpa sinkronisasi. Ini akan terjadi semua contoh berikut - acara mungkin berbeda.

2.

2

Di sini acara timeout memainkan peran, yang akan memanggil pawang setelah waktu yang ditentukan. Ini dia 0, tapi tetap saja mendaftarkan peristiwa asinkron itu akan ditambahkan ke posisi terakhir dari Event Queueeksekusi, yang membuat penundaan dijamin.

3.

masukkan deskripsi gambar di sini Kali ini ajax callback.

4.

masukkan deskripsi gambar di sini

Node dapat dianggap sebagai raja pengkodean asinkron. Di sini fungsi yang ditandai terdaftar sebagai penangan panggilan balik yang akan dieksekusi setelah membaca file yang ditentukan.

5.

masukkan deskripsi gambar di sini

Janji yang jelas (sesuatu akan dilakukan di masa depan) tidak sinkron. lihat Apa perbedaan antara Ditangguhkan, Berjanji dan Masa Depan dalam JavaScript?

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.