Saya memiliki beberapa kode JavaScript yang terlihat seperti:
function statechangedPostQuestion()
{
//alert("statechangedPostQuestion");
if (xmlhttp.readyState==4)
{
var topicId = xmlhttp.responseText;
setTimeout("postinsql(topicId)",4000);
}
}
function postinsql(topicId)
{
//alert(topicId);
}
Saya mendapatkan kesalahan yang topicId
tidak didefinisikan. Semuanya berfungsi sebelum saya menggunakan setTimeout()
fungsi.
Saya ingin postinsql(topicId)
fungsi saya dipanggil setelah beberapa waktu. Apa yang harus saya lakukan?
javascript
parameters
callback
settimeout
Zeeshan Rang
sumber
sumber
Jawaban:
Anda perlu memberi makan fungsi anonim sebagai parameter alih-alih sebuah string, metode yang terakhir bahkan tidak akan bekerja sesuai spesifikasi skrip ECMAS tetapi browser hanya lunak. Ini adalah solusi yang tepat, jangan pernah mengandalkan meneruskan string sebagai 'fungsi' saat menggunakan
setTimeout()
atausetInterval()
, itu lebih lambat karena harus dievaluasi dan itu tidak benar.MEMPERBARUI:
Seperti yang dikatakan Hobblin dalam komentarnya terhadap pertanyaan, sekarang Anda dapat meneruskan argumen ke fungsi di dalam setTimeout menggunakan
Function.prototype.bind()
.Contoh:
sumber
window.setTimeout
adalah metode DOM, dan karenanya tidak ditentukan oleh spesifikasi skrip ECMAS. Melewati string selalu berfungsi di browser, dan merupakan standar de facto — pada kenyataannya, kemampuan untuk melewatkan objek fungsi ditambahkan kemudian, dengan JavaScript 1.2 — itu secara eksplisit merupakan bagian dari spesifikasi draft HTML5 ( whatwg.org/specs/web -apps / current-work / multipage / ... ). Namun, menggunakan string sebagai ganti objek fungsi umumnya dianggap gaya buruk karena pada dasarnya merupakan bentuk yang tertundaeval()
.Di browser modern, "setTimeout" menerima parameter ketiga yang dikirim sebagai parameter ke fungsi internal di akhir penghitung waktu.
Contoh:
Keterangan lebih lanjut:
sumber
Setelah melakukan beberapa penelitian dan pengujian, satu-satunya implementasi yang benar adalah:
setTimeout akan meneruskan semua parameter tambahan ke fungsi Anda sehingga dapat diproses di sana.
Fungsi anonim dapat bekerja untuk hal-hal yang sangat mendasar, tetapi dalam contoh objek di mana Anda harus menggunakan "ini", tidak ada cara untuk membuatnya berfungsi. Setiap fungsi anonim akan mengubah "ini" untuk menunjuk ke jendela, sehingga Anda akan kehilangan referensi objek Anda.
sumber
var that = this; setTimeout( function() { that.foo(); }, 1000);
Ini adalah pertanyaan yang sangat lama dengan jawaban yang sudah "benar" tetapi saya pikir saya akan menyebutkan pendekatan lain yang tidak ada yang disebutkan di sini. Ini disalin dan ditempel dari perpustakaan garis bawah yang sangat baik :
Anda bisa memberikan argumen sebanyak yang Anda inginkan ke fungsi yang dipanggil oleh setTimeout dan sebagai bonus tambahan (well, biasanya bonus) nilai argumen yang dilewatkan ke fungsi Anda dibekukan saat Anda memanggil setTimeout, jadi jika mereka mengubah nilai di beberapa titik antara ketika setTimeout () dipanggil dan ketika waktu habis, yah ... itu tidak terlalu membuat frustrasi lagi :)
Ini biola di mana Anda bisa melihat apa yang saya maksud.
sumber
Saya baru-baru ini menemukan situasi unik yang perlu digunakan
setTimeout
dalam satu lingkaran . Memahami hal ini dapat membantu Anda memahami cara meneruskan parametersetTimeout
.Metode 1
Gunakan
forEach
danObject.keys
, sesuai saran Sukima :Saya merekomendasikan metode ini.
Metode 2
Gunakan
bind
:JSFiddle: http://jsfiddle.net/MsBkW/
Metode 3
Atau jika Anda tidak dapat menggunakan
forEach
ataubind
, gunakan IIFE :Metode 4
Tetapi jika Anda tidak peduli tentang IE <10, maka Anda dapat menggunakan saran Fabio :
Metode 5 (ES6)
Gunakan variabel scoped blok:
Meskipun saya masih akan merekomendasikan menggunakan
Object.keys
denganforEach
ES6.sumber
.bind
tidak akan berfungsi untuk IE8 dan di bawah ini [ref: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ]. Saya akhirnya menggunakan solusi Schien: stackoverflow.com/a/21213723/1876899bind
maka Anda juga berada dalam lingkungan yang menawarkanObject.keys
danforEach
. Anda dapat kehilangan for for loop dan mendapatkan lingkup fungsi "bebas" (seperti pada dua burung dengan satu batu gratis bukan bebas sumber daya) dalam proses.async
perpustakaan ( github.com/caolan/async ). Kami menggunakannya secara luas dalam Sails dan memiliki hasil yang bagus selama 2 tahun terakhir. Ini menyediakan metode di kedua paralel dan seri untuk asynchronousforEach
,map
,reduce
, dllHobblin sudah mengomentari ini pada pertanyaan, tetapi itu harus benar-benar menjadi jawaban!
Menggunakan
Function.prototype.bind()
adalah cara paling bersih dan paling fleksibel untuk melakukan ini (dengan bonus tambahan untuk dapat mengaturthis
konteks):Untuk informasi lebih lanjut, lihat tautan MDN ini:
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041 https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Function / bind # With_setTimeout
sumber
setTimeout(postinsql.bind(this, topicId), 4000);
bind
. Itu benar-benar membuat beberapa kode dapat dibaca.Beberapa jawaban benar tetapi berbelit-belit.
Saya menjawab ini lagi, 4 tahun kemudian, karena saya masih mengalami kode yang terlalu rumit untuk menyelesaikan pertanyaan ini. ADA solusi yang elegan.
Pertama-tama, jangan berikan string sebagai parameter pertama saat memanggil setTimeout karena secara efektif memanggil panggilan ke fungsi "eval" yang lambat.
Jadi, bagaimana kita mengirimkan parameter ke fungsi batas waktu? Dengan menggunakan penutupan:
Beberapa menyarankan menggunakan fungsi anonim saat memanggil fungsi batas waktu:
Sintaksnya berhasil. Tetapi pada saat settopic dipanggil, yaitu 4 detik kemudian, objek XHR mungkin tidak sama. Karena itu penting untuk melakukan pre-bind variabel .
sumber
Jawabanku:
Penjelasan:
ATAU
Ini pada dasarnya dikonversi ke:
EDIT: Saya melihat jawaban yang sama, jadi lihatlah jawabannya. Tapi aku tidak mencuri jawabannya! Saya hanya lupa melihat. Baca penjelasannya dan lihat apakah ada baiknya memahami kodenya.
sumber
topicId
diubah nilai dalam batas waktu juga berubah. Sebuah klon memperbaikinyaMenggantikan
dengan
atau lebih baik lagi, ganti ekspresi string dengan fungsi anonim
EDIT:
Komentar Brownstone salah, ini akan berfungsi sebagaimana dimaksud, seperti yang ditunjukkan dengan menjalankan ini di konsol Firebug
Perhatikan bahwa saya setuju dengan orang lain bahwa Anda harus menghindari meneruskan string
setTimeout
karena ini akan memanggileval()
string dan alih-alih meneruskan fungsi.sumber
Anda dapat meneruskan parameter ke fungsi panggilan balik setTimeout sebagai:
setTimeout (fungsi, milidetik, param1, param2, ...)
misalnya.
sumber
setTimeout( (p) => { console.log(p); }, 1000, "hi" );
Solusi lintas browser termudah untuk mendukung parameter di setTimeout:
Jika Anda tidak keberatan tidak mendukung IE 9 dan lebih rendah:
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
sumber
Saya tahu sudah 10 tahun sejak pertanyaan ini diajukan, tetapi tetap saja, jika Anda telah menggulir sampai di sini, saya menganggap Anda masih menghadapi beberapa masalah. Solusi oleh Meder Omuraliev adalah yang paling sederhana dan dapat membantu sebagian besar dari kita tetapi bagi mereka yang tidak ingin memiliki ikatan apa pun, ini dia:
sumber
Saya tahu ini sudah tua tetapi saya ingin menambahkan rasa (pilihan) saya pada ini.
Saya pikir cara yang cukup mudah dibaca untuk mencapai ini adalah dengan meneruskan
topicId
ke fungsi, yang pada gilirannya menggunakan argumen untuk referensi ID topik secara internal. Nilai ini tidak akan berubah bahkan jikatopicId
di luar akan diubah segera setelahnya.atau pendek:
sumber
Jawaban oleh David Meister tampaknya menangani parameter yang dapat berubah segera setelah panggilan ke setTimeout () tetapi sebelum fungsi anonim dipanggil. Tapi itu terlalu rumit dan tidak terlalu jelas. Saya menemukan cara yang elegan untuk melakukan hal yang hampir sama dengan menggunakan IIFE (ekspresi fungsi langsung inviked).
Dalam contoh di bawah ini,
currentList
variabel dilewatkan ke IIFE, yang menyimpannya dalam penutupannya, sampai fungsi tertunda dipanggil. Bahkan jika variabelcurrentList
berubah segera setelah kode ditampilkan,setInterval()
akan melakukan hal yang benar.Tanpa teknik IIFE ini,
setTimeout()
fungsi pasti akan dipanggil untuk setiaph2
elemen di DOM, tetapi semua panggilan itu hanya akan melihat nilai teks dari elemen terakhirh2
.sumber
Secara umum, jika Anda harus meneruskan fungsi sebagai panggilan balik dengan parameter tertentu, Anda dapat menggunakan fungsi urutan yang lebih tinggi. Ini cukup elegan dengan ES6:
Atau jika
someFunction
urutan pertama:sumber
Perhatikan bahwa alasan topicId "tidak didefinisikan" per pesan kesalahan adalah bahwa itu ada sebagai variabel lokal ketika setTimeout dieksekusi, tetapi tidak ketika panggilan tertunda ke postinsql terjadi. Variabel seumur hidup sangat penting untuk diperhatikan, terutama ketika mencoba sesuatu seperti melewatkan "ini" sebagai referensi objek.
Saya mendengar bahwa Anda dapat meneruskan topicId sebagai parameter ketiga ke fungsi setTimeout. Tidak banyak detail diberikan tetapi saya mendapat informasi yang cukup untuk membuatnya berfungsi, dan itu berhasil di Safari. Saya tidak tahu apa artinya tentang "kesalahan milidetik". Lihat disini:
http://www.howtocreate.co.uk/tutorials/javascript/timers
sumber
Bagaimana saya menyelesaikan tahap ini?
seperti itu :
setTimeout menunggu referensi ke suatu fungsi, jadi saya membuatnya dalam penutup, yang menginterpretasikan data saya dan mengembalikan fungsi dengan contoh data saya yang bagus!
Mungkin Anda bisa memperbaiki bagian ini:
Saya mengujinya pada chrome, firefox dan IE dan itu berjalan dengan baik, saya tidak tahu tentang kinerja tetapi saya membutuhkannya untuk bisa bekerja.
tes sampel:
Mungkin Anda dapat mengubah tanda tangan agar lebih patuh:
Dan akhirnya menjawab pertanyaan asli:
Semoga bisa membantu!
ps: maaf tapi bahasa Inggris itu bukan bahasa ibu saya!
sumber
ini bekerja di semua browser (IE adalah sebuah ganjil)
sumber
jika Anda ingin meneruskan variabel sebagai param mari kita coba ini
jika persyaratan adalah fungsi dan var sebagai parmas maka coba ini
jika persyaratan hanya variabel sebagai params maka coba ini
Anda dapat mencoba ini dengan ES5 dan ES6
sumber
Anda dapat mencoba fungsionalitas default dari 'apply ()' sesuatu seperti ini, Anda dapat memberikan lebih banyak argumen sebagai kebutuhan Anda dalam array
sumber
setTimeout adalah bagian dari DOM yang ditentukan oleh WHAT WG.
https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html
Metode yang Anda inginkan adalah: -
Rupanya, argumen tambahan didukung di IE10. Atau, Anda dapat menggunakan
setTimeout(postinsql.bind(null, topicId), 4000);
, namun memberikan argumen tambahan lebih sederhana, dan itu lebih disukai.Fakta historis: Dalam hari-hari VBScript, dalam JScript, parameter ketiga setTimeout adalah bahasa, sebagai string, default ke "JScript" tetapi dengan opsi untuk menggunakan "VBScript". https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa741500(v%3Dvs.85)
sumber
@Jiri Vetyska terima kasih atas kirimannya, tetapi ada sesuatu yang salah dalam contoh Anda. Saya perlu melewati target yang melayang-layang (ini) ke fungsi time-out dan saya mencoba pendekatan Anda. Diuji dalam IE9 - tidak bekerja. Saya juga melakukan riset dan tampaknya seperti ditunjukkan di sini parameter ketiga adalah bahasa skrip yang digunakan. Tidak disebutkan tentang parameter tambahan.
Jadi, saya mengikuti jawaban @ meder dan menyelesaikan masalah saya dengan kode ini:
Semoga ini bermanfaat bagi orang lain.
sumber
Karena ada masalah dengan parameter optonal ketiga di IE dan menggunakan penutupan mencegah kita dari mengubah variabel (dalam satu lingkaran misalnya) dan masih mencapai hasil yang diinginkan, saya menyarankan solusi berikut.
Kita dapat mencoba menggunakan rekursi seperti ini:
Kita perlu memastikan bahwa tidak ada lagi yang mengubah variabel-variabel ini dan bahwa kita menulis kondisi rekursi yang tepat untuk menghindari rekursi tak terbatas.
sumber
// Ini adalah tiga jawaban yang sangat sederhana dan ringkas:
sumber
Menjawab pertanyaan tetapi dengan fungsi penambahan sederhana dengan 2 argumen.
sumber
Anda harus menghapus tanda kutip dari
setTimeOut
panggilan fungsi Anda seperti ini:sumber
Saya pikir Anda ingin:
sumber
JSON.stringify
untuk objek dan array biasa, lalu gunakanJSON.parse
di dalam fungsi. Namun, semua perilaku akan hilang jika objek memiliki metode.// Ini adalah tiga jawaban yang sangat sederhana dan ringkas:
sumber