Javascript'teki zamanlayıcılar (setInterval, setTimeout). JavaScript zamanlayıcılarının nasıl çalıştığı hakkında Eylemleri belirli bir zaman aralığında tekrarlayın javascript

  • İtibaren:
  • Kayıtlı: 2014.07.08
  • Gönderiler: 3.896
  • Beğeniler: 497
Konu: SetTimeOut ve SetInterval, JavaScript'te hangisinin kullanılması daha iyidir?

setInterval işlevi, kodu düzenli aralıklarla birden çok kez çalıştıracak şekilde tasarlanmıştır. Bununla birlikte, başta farklı davranışlar olmak üzere bir takım dezavantajları vardır. farklı tarayıcılar.

İlk fark, zamanlayıcının bir sonraki başlatma için ayarlandığı zamandaki farktır. Küçük bir test oluşturalım: Önceki çalışmanın başlangıcından bu yana ve bitişinden bu yana geçen süreyi ölçeceğiz.

var d1 = yeni Tarih(), d2 = yeni Tarih(); setInterval(function() ( var d = new Date(); document.body.innerHTML += (d - d1) + " " + (d - d2) + "
"; // Fonksiyonun başına bir işaret koyun d1 = new Date(); while (new Date() - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

Çıktı ikinci satırdan itibaren bilgilendirici olacaktır.

Firefox, Opera, Safari ve Chrome'da da durum benzer olacaktır: ilk sayı yaklaşık olarak 1000'e eşit olacak, ikincisi ise 200 daha az olacak. Tek fark değerlerin yayılmasında olacaktır. En küçük fark Chrome ve Opera'dadır.

2 PunBB'nin yanıtı (PunBB tarafından düzenlenmiştir 2017.06.08 16:45)
  • Nereden: Moskova, Sovkhoznay 3, daire. 98
  • Kayıtlı: 2014.07.08
  • Gönderiler: 3.896
  • Beğeniler: 497

Daha az fark edilen ve yeniden üretilmesi daha zor olan ancak bazen çok fazla soruna neden olabilen bir diğer fark ise sistem zamanı değişikliklerine karşı dirençtir. Aşağıdaki testi çalıştırırsanız

setInterval(function() ( document.body.innerHTML = Math.random(); ), 500);

Başladıktan sonra sistem saatini bir dakika geriye ayarlayın, ardından Firefox ve Safari tarayıcılarında sayı değişikliği duraklayacak ve bir dakika sonra yeniden başlayacaktır. Elbette sistem zamanının manuel olarak çevrilmesi son derece nadir bir durumdur, ancak birçok sistem zamanı İnternet'teki sunucularla otomatik olarak senkronize edecek şekilde yapılandırılmıştır, bu nedenle bazı durumlarda bu faktör göz ardı edilemez.

setInterval fonksiyonunun bir diğer küçük dezavantajı, eylemini durdurabilmek için tanımlayıcısını bir yerde hatırlamanız gerekmesidir ki bu her zaman uygun değildir.

3 PunBB'nin yanıtı
  • Nereden: Moskova, Sovkhoznay 3, daire. 98
  • Kayıtlı: 2014.07.08
  • Gönderiler: 3.896
  • Beğeniler: 497
Yanıt: SetTimeOut ve SetInterval, JavaScript'te hangisinin kullanılması daha iyidir?

setInterval'ın listelenen dezavantajlarından kurtulmak için birden fazla setTimeout kullanabilirsiniz.

setInterval'ın önemli bir alternatifi yinelemeli setTimeout'tur:

/** bunun yerine: var timerId = setInterval(function() ( warning("tick"); ), 2000); */ var timerId = setTimeout(function Tick() ( warning("tick"); timerId = setTimeout(tick, 2000); ), 2000);

Yukarıdaki kodda, bir sonraki yürütme önceki yürütmenin bitiminden hemen sonra planlanır.

Özyinelemeli setTimeout, setInterval'a göre daha esnek bir zamanlama yöntemidir, çünkü bir sonraki yürütmeye kadar geçen süre, mevcut yürütmenin sonuçlarına bağlı olarak farklı şekilde programlanabilir.

Örneğin, her 5 saniyede bir yeni veriler için sunucuyu yoklayan bir hizmetimiz var. Sunucu aşırı yüklenmişse yoklama aralığını 10, 20, 60 saniyeye artırabilirsiniz... Ve her şey normale döndüğünde geri döndürebilirsiniz.

CPU'yu yoğun olarak kullanan görevleri düzenli olarak çalıştırıyorsak, bunların yürütülmesi için harcanan süreyi tahmin edebilir ve bir sonraki çalıştırmayı erken veya geç planlayabiliriz.

4 PunBB'nin yanıtı
  • Nereden: Moskova, Sovkhoznay 3, daire. 98
  • Kayıtlı: 2014.07.08
  • Gönderiler: 3.896
  • Beğeniler: 497
Yanıt: SetTimeOut ve SetInterval, JavaScript'te hangisinin kullanılması daha iyidir?

Özyinelemeli setTimeout çağrılar arasında bir duraklamayı garanti eder, setInterval bunu garanti etmez.

İki kodu karşılaştıralım. İlki setInterval'ı kullanır:

var i = 1; setInterval(function() ( func(i); ), 100);

İkincisi yinelemeli bir setTimeout kullanır:

var i = 1; setTimeout(function run() ( func(i); setTimeout(run, 100); ), 100);

setInterval ile dahili zamanlayıcı tam olarak her 100 ms'de bir etkinleşecek ve func(i)'yi çağıracaktır:

setInterval ile işlev çağrıları arasındaki gerçek duraklama, kodda belirtilenden daha azdır!

Bu doğaldır, çünkü fonksiyonun çalışma süresi hiçbir şekilde dikkate alınmaz; aralığın bir kısmını "tüketir".

İşlevin beklediğimizden daha karmaşık olması ve yürütülmesinin 100 ms'den uzun sürmesi de mümkündür.

Bu durumda, yorumlayıcı işlevin tamamlanmasını bekleyecek, ardından zamanlayıcıyı kontrol edecek ve eğer setInterval'ı çağırma zamanı zaten gelmişse (veya geçmişse), bir sonraki çağrı hemen gerçekleşecektir.

Eğer fonksiyon setInterval duraklamasından daha uzun süre çalışırsa çağrılar herhangi bir kesinti olmadan gerçekleşir.

5 sempai'nin yanıtı
  • Nereden: Kudüs
  • Kayıtlı: 02.06.2015
  • Gönderiler: 958
  • Beğeniler: 274
Yanıt: SetTimeOut ve SetInterval, JavaScript'te hangisinin kullanılması daha iyidir?

Her şey eldeki göreve bağlıdır. Başlangıçta, SetTimeOut zamanlayıcıyı bir kez başlatmak için kullanılır ve SetInterval bir döngü başlatmak için kullanılır. Ancak her iki işlev de komut dosyalarını döngüsel olarak çalıştırmak için kullanılabilir; örneğin bunları SetTimeOut işlevinde yinelemeli olarak çalıştırırsanız, SetInterval'a neredeyse benzer şekilde davranırlar.

Şu anda SetInterval'in dezavantajı, betiğin (işlev) kendisinin yürütme süresini hesaba katmaması ve örneğin onu ağır sorgular için kullanırsanız, aralık süresinin önemli ölçüde azalması ve farklı tarayıcılarda farklılık gösterebilir.

Ancak yine de, işlev veya istek en aza indirilirse son kullanıcının farkı hissetmesi pek olası değildir.
Bu nedenle ne kullanılacağına herkesin kendisi karar verecektir.

JavaScript zaman aşımı, belirli bir zaman gecikmesinden sonra (milisaniye cinsinden) bir kod parçasını çalıştıran yerel bir javascript işlevidir. Kullanıcı sayfanızda biraz zaman geçirdikten sonra bir açılır pencere görüntülemeniz gerektiğinde bu kullanışlı olabilir. Yoksa bir öğenin üzerine geldiğinizde efektin ancak bir süre geçtikten sonra mı başlamasını istiyorsunuz? Bu şekilde, kullanıcının yanlışlıkla üzerine gelmesi durumunda bir efektin istemeden tetiklenmesini önleyebilirsiniz.

Basit setTimeout örneği

Bu özelliğin nasıl çalıştığını göstermek için, düğmeye tıklandıktan iki saniye sonra bir açılır pencerenin göründüğü aşağıdaki demoya göz atmanızı öneririm.

Demoyu görüntüle

Sözdizimi

MDN belgeleri setTimeout için aşağıdaki sözdizimini sağlar:

var timeoutID = window.setTimeout(func, ); var timeoutID = window.setTimeout(kod, );

  • timeoutID – zamanlayıcıyı devre dışı bırakmak için clearTimeout() ile birlikte kullanılabilen sayısal bir kimlik;
  • func – yürütülecek işlev;
  • kod (alternatif sözdiziminde) – yürütülecek kod satırı;
  • gecikme – işlevin başlatılacağı gecikmenin milisaniye cinsinden süresi. Varsayılan değer 0'dır.
setTimeout vs window.setTimeout

Yukarıdaki sözdizimi window.setTimeout öğesini kullanır. Neden?

Aslında setTimeout ve window.setTimeout neredeyse aynı işlevdir. Tek fark, ikinci ifadede global window nesnesinin bir özelliği olarak setTimeout yöntemini kullanmamızdır.

Kişisel olarak bunun kodu çok daha karmaşık hale getirdiğini düşünüyorum. Bir alternatif tanımlayacak olsaydık JavaScript yöntemi timeout öncelik sırasına göre bulunup döndürülebilirse, daha da fazla sorunla karşılaşırız.

İÇİNDE bu kılavuz Window nesnesiyle uğraşmak istemiyorum ama genel olarak hangi sözdizimini kullanacağınız size kalmış.

Kullanma örnekleri

Bu fonksiyonun adı olabilir:

function patlama())( warning("Boom!"); ) setTimeout(patlama, 2000);

Fonksiyona atıfta bulunan değişken:

var patlayabilir = function())( warning("Boom!"); ); setTimeout(patlama, 2000);

Veya anonim bir işlev:

setTimeout(function())( warning("Boom!"); ), 2000);

  • Bu tür kodlar yeterince anlaşılmamıştır ve bu nedenle modernleştirilmesi veya hatalarının ayıklanması zor olacaktır;
  • Potansiyel bir güvenlik açığı olabilecek eval() yönteminin kullanımını içerir;
  • Bu yöntem diğerlerinden daha yavaştır çünkü JavaScript yorumlayıcısının çalıştırılmasını gerektirir.

Ayrıca kodu test etmek için JavaScript zaman aşımı uyarı yöntemini kullandığımızı unutmayın.

Parametrelerin setTimout'a aktarılması

İlk (ve çapraz tarayıcı) seçeneğinde, setTimeout kullanılarak yürütülen geri çağırma işlevine parametreler iletiriz.

Aşağıdaki örnekte, tebrik dizisinden rastgele bir selamlama çıkarıp bunu setTimeout tarafından 1 saniyelik bir gecikmeyle yürütülen greet() fonksiyonuna parametre olarak iletiyoruz:

function greet(selamlama)( console.log(selamlama); ) function getRandom(arr)( return arr; ) var tebrikler = ["Merhaba", "Bonjour", "Guten Etiketi"], randomGreeting = getRandom(selamlar); setTimeout(function())( greet(randomGreeting); ), 1000);

Demoyu görüntüle

Alternatif yöntem

Yazının başında verilen söz diziminde, JavaScript timeout tarafından çalıştırılan geri çağırma fonksiyonuna parametre iletebileceğiniz başka bir yöntem daha bulunmaktadır. Bu method gecikmeyi takiben tüm parametrelerin çıktısını ifade eder.

Önceki örneğe dayanarak şunu elde ederiz:

setTimeout(selamlama, 1000, rastgeleGreeting);

Bu yöntem IE 9 ve altında çalışmaz; geçirilen parametreler tanımlanmamış olarak kabul edilir. Ancak MDN'de bu sorunu çözmek için özel bir çoklu doldurma var.

İlgili sorunlar ve “bu”

setTimeout tarafından yürütülen kod, onu çağıran işlevden ayrı olarak çalışır. Bu nedenle this anahtar sözcüğü kullanılarak çözülebilecek bazı sorunlarla karşılaşıyoruz.

var kişi = ( ad: "Jim", tanıtım: function())( console.log("Merhaba, ben"m " + bu.ilkAd); ) ); kişi.introduce(); // Çıkışlar: Merhaba, I " m Jim setTimeout(person.introduce, 50); // Çıkışlar: Merhaba, tanımsızım

Bu çıktının nedeni, ilk örnekte bunun kişi nesnesini, ikinci örnekte ise FirstName özelliği olmayan global window nesnesini işaret etmesidir.

Bu tutarsızlıktan kurtulmak için birkaç yöntem kullanabilirsiniz:

Bunu ayarlamaya zorla

Bu, aşağıdakileri oluşturan bir yöntem olan bağlama() kullanılarak yapılabilir: yeni özellik, bu anahtarın değeri olarak çağrıldığında şunu kullanır: belirli değer. Bizim durumumuzda belirtilen kişi itiraz ediyor. Bu sonuçta bize şunu veriyor:

setTimeout(person.introduce.bind(kişi), 50);

Not: bağlama yöntemi ECMAScript 5'te tanıtıldı; bu, yalnızca modern tarayıcılarda çalışacağı anlamına gelir. Diğerlerinde, onu kullandığınızda, “işlev zaman aşımı hatası” adlı bir JavaScript yürütme hatası alırsınız.

Kitaplığı kullan

Pek çok kitaplık bu sorunu çözmek için gereken yerleşik işlevleri içerir. Örneğin, jQuery.proxy() yöntemi. Bir işlevi alır ve her zaman belirli bir bağlamı kullanacak yeni bir işlev döndürür. Bizim durumumuzda bağlam şöyle olacaktır:

setTimeout($.proxy(person.introduce, kişi), 50);

Demoyu görüntüle

Zamanlayıcıyı devre dışı bırakma

setTimeout'un dönüş değeri, clearTimeout() işlevini kullanarak zamanlayıcıyı devre dışı bırakmak için kullanılabilecek sayısal bir kimliktir:

var timer = setTimeout(myFunction, 3000); clearTimeout(zamanlayıcı);

Uygulamalı olarak görelim. Aşağıdaki örnekte “Geri sayımı başlat” butonuna tıklarsanız geri sayım başlayacaktır. Tamamlandıktan sonra yavru kediler kendilerine ait olacak. Ancak “Geri sayımı durdur” butonuna tıklarsanız, JavaScript zaman aşımı zamanlayıcısı durdurulacak ve sıfırlanacaktır.

Örneği görüntüle

Özetleyelim

setTimeout eşzamansız bir işlevdir; bu, bu işleve yapılan çağrının bir kuyruğa gireceği ve yalnızca yığındaki diğer tüm eylemler tamamlandıktan sonra yürütüleceği anlamına gelir. Diğer işlevlerle veya ayrı bir iş parçacığıyla aynı anda çalışamaz.

Window ve Worker arayüzlerinde sunulan setInterval() yöntemi, her çağrı arasında sabit bir zaman gecikmesiyle tekrar tekrar bir işlevi çağırır veya bir kod parçacığını çalıştırır. Aralığı benzersiz şekilde tanımlayan bir aralık kimliği döndürür; böylece daha sonra clearInterval() öğesini çağırarak onu kaldırabilirsiniz. Bu yöntem WindowOrWorkerGlobalScope karışımı tarafından tanımlanır.

Sözdizimi var intervalID = kapsam.setInterval( işlev, gecikme, [arg1, arg2, ...]); var intervalID = kapsam.setInterval( kod, gecikme); Parametreler func Her milisaniye gecikmede yürütülecek bir işlev. İşleve herhangi bir argüman iletilmez ve herhangi bir dönüş değeri beklenmez. code İsteğe bağlı bir sözdizimi, her milisaniyede bir gecikmeyle derlenen ve yürütülen bir işlev yerine bir dize eklemenize olanak tanır. Bu sözdizimi tavsiye edilmez eval() kullanımını bir güvenlik riski haline getiren aynı nedenlerden dolayı. gecikme Milisaniye cinsinden (saniyenin binde biri) süre, zamanlayıcının belirtilen işlev veya kodun yürütülmesi arasında gecikmesi gerekir. İzin verilen gecikme değerleri aralığına ilişkin ayrıntılar için aşağıya bakın. arg1, ..., argN İsteğe Bağlı Şununla belirtilen işleve iletilen ek bağımsız değişkenler: işlev zamanlayıcının süresi dolduğunda.

Not: İlk sözdiziminde setInterval() işlevine ek argümanlar iletmek, İnternet Explorer 9 ve öncesi. Bu işlevi söz konusu tarayıcıda etkinleştirmek istiyorsanız çoklu doldurma kullanmanız gerekir (bölüme bakın).

Geri dönüş değeri

Döndürülen intervalID, setInterval() çağrısı tarafından oluşturulan zamanlayıcıyı tanımlayan, sıfır olmayan sayısal bir değerdir; Bu değer, zaman aşımını iptal etmek için iletilebilir.

setInterval() ve setTimeout() öğelerinin aynı kimlik havuzunu paylaştığını ve clearInterval() ile clearTimeout() öğelerinin teknik olarak birbirlerinin yerine kullanılabileceğini bilmek faydalı olabilir. Ancak netlik sağlamak adına, kodunuzu korurken karışıklığı önlemek için her zaman bunları eşleştirmeye çalışmalısınız.

Not: Gecikme argümanı imzalı 32 bitlik bir tamsayıya dönüştürülür. Bu, IDL'de işaretli bir tamsayı olarak belirtildiğinden, gecikmeyi etkili bir şekilde 2147483647 ms ile sınırlandırır.

Örnekler Örnek 1: Temel sözdizimi

Aşağıdaki örnek setInterval() "ın temel sözdizimini göstermektedir.

Var intervalID = window.setInterval(myCallback, 500, "Parametre 1", "Parametre 2"); function myCallback(a, b) ( // Kodunuz burada // Parametreler tamamen isteğe bağlıdır. console.log(a); console.log(b); )

Örnek 2: İki rengi değiştirme

Aşağıdaki örnek, Durdur düğmesine basılana kadar saniyede bir kez flashtext() işlevini çağırır.

setInterval/clearInterval örneği var nIntervId; function changeColor() ( nIntervId = setInterval(flashText, 1000); ) function flashText() ( var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "kırmızı" ? " blue" : "red"; // oElem.style.color == "red" ? "blue" : "red" üçlü bir operatördür. ) function stopTextColor() ( clearInterval(nIntervId); )

Selam Dünya

Durmak

Örnek 3: Daktilo simülasyonu

Aşağıdaki örnek, belirli bir seçici grubuyla eşleşen NodeList'teki içeriği önce temizleyip ardından yavaşça yazarak daktiloyu simüle eder.

JavaScript Daktilo - MDN Örnek fonksiyon Daktilo (sSelector, nRate) ( function clean () ( clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; ) function kaydırma (oSheet, nPos) , bEraseAndStop) ( if (!oSheet.hasOwnProperty("parçalar") || aMap.length< nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap < oSheet.parts.length) { oRel = oSheet.parts]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets, 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts); this.parts = new Sheet(this.parts); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = , aMap = ; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems)); /* Uncomment the following line if you have previously hidden your elements via CSS: */ // aItems.style.visibility = "visible"; } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets, 0, false)); clean(); }; } /* usage: */ var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */ var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */ // oTWExample2.rate = 150; onload = function () { oTWExample1.play(); oTWExample2.play(); }; span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline; } #info { width: 180px; height: 150px; float: right; background-color: #eeeeff; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px; /* visibility: hidden; */ }

CopyLeft 2012 Mozilla Geliştirici Ağı tarafından

[ Oynat | Duraklat | Sonlandır]

Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Bir arabaya binmeden önce. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. Tincidunt tincidunt tincidunt'ta. JavaScript Daktilo

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam, uygunsuz bir şekilde çalışıyor. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque sakini morbi tristique senectus et netus et malesuada, turpis egestas ile ünlüdür. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, bir özgeçmişe sahip ol, ipsum olmadan volutpat.

Phasellus ac nisl lorem:
Nullam commodo suscipit lacus non aliquet. Phasellus ac nisl lorem, sed facilisis ligula. Nam cursus lobortis placerat. Sed dui nisi, elementum eu sodales ac, placerat sit amet mauris. Pellentesque dapibus bize tüm ipsum aliquam eu auctor dui tool'u anlatıyor. Quisque ultrices laoreet dönemi, at ultrices tortor sodales non. Sed venenatis luctus magna, ultricies ultricies nunc fringilla eget. Praesent scelerisque urna vitae nibh tristique varius consequat neque luctus. Tamsayı ornare, bir porta tempus, velit justo fermentum elit, bir fermentum metus nisi eu ipsum. Vivamus eget augue vel dui viverra adipiscing congue ut massa. Praesent vitae eros dönemi, pulvinar laoreet magna. Maecenas vestibulum mollis nunc in posuere. Pellentesque sit amet metus a turpis lobortis tempor eu vel tortor. Cras sodales eleifend interdum.

Duis lobortis sapien quis nisl luctus porttitor. Tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida başka yerde sınıflandırılmamış. Curabitur elementum nisi ve eros rutrum nec bladit diam placerat. Aenean tincidunt, ut nisi consectetur cursus'u yükseltiyor. Elit bir hayat. Donec saygınlığı, zamanla bunun bir sonucu olarak ortaya çıktı. Aliquam aliquam diam non felis convallis suscipit. Hiçbir şey yok. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.

Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus dönemi, vel çeşitli işkence patlamaları ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Başka bir özgürlük yok. Hiçbir şey yapılmadı, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem araç egestas.

Geri arama argümanları

Daha önce tartışıldığı gibi, Internet Explorer sürüm 9 ve altı, setTimeout() veya setInterval() işlevlerinde argümanların geri çağırma işlevine iletilmesini desteklemez. Aşağıdaki IE'ye özgü kod, bu sınırlamanın üstesinden gelmeye yönelik bir yöntemi gösterir. Kullanmak için aşağıdaki kodu betiğinizin üstüne eklemeniz yeterlidir.

/*\ |*| |*| Rastgele argümanların |*|'ye geçişini sağlayan IE'ye özgü çoklu doldurma javascript zamanlayıcıların geri çağırma işlevleri (HTML5 standart sözdizimi)..setInterval |*| https://site/Kullanıcı:fusionchess |*| |*| Söz dizimi: |*| var timeoutID = window.setTimeout(func, gecikme[, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout(kod, gecikme); |*| var intervalID = window.setInterval(func, gecikme[, arg1, arg2, ...]); |*| var intervalID = window.setInterval(kod, gecikme); |*| \*/ if (document.all && !window.setTimeout.isPolyfill) ( var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, ArgümanToPass1, ArgümanToPass2, vb. */) ( var aArgs = Array .prototype.slice.call(arguments, 2); return __nativeST__(vCallback Instanceof Function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay ); if (document.all && !window.setInterval.isPolyfill) ( var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argümanToPass1, argümanToPass2, vb. */) ( var aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback) Instanceof Function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay );

Diğer bir olasılık da geri aramanızı yapmak için anonim bir işlev kullanmaktır, ancak bu çözüm biraz daha pahalıdır. Örnek:

Var intervalID = setInterval(function() ( myFunc("bir", "iki", "üç"); ), 1000); var intervalID = setInterval(function(arg1) ().bind(tanımsız, 10), 1000);

Etkin olmayan sekmeler Gecko 5.0 gerektirir(Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2)

Gecko 5.0'dan (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) başlayarak, aralıklar etkin olmayan sekmelerde saniyede bir defadan daha sık tetiklenmeyecek şekilde sabitlenir.

"Bu" sorunu

Bir yöntemi setInterval()'a veya başka bir işleve ilettiğinizde, yanlış this değeriyle çağrılır. Bu sorun, JavaScript referansında ayrıntılı olarak açıklanmaktadır.

Açıklama

setInterval() tarafından yürütülen kod, çağrıldığı işlevden farklı bir yürütme bağlamında çalışır. Sonuç olarak, çağrılan işlevin this anahtar sözcüğü window (veya global) nesnesine ayarlanmıştır; setTimeout olarak adlandırılan işlevin this değeriyle aynı değildir. Aşağıdaki örneğe bakın (setInterval() yerine setTimeout() işlevini kullanır; aslında sorun her iki zamanlayıcı için de aynıdır):

Dizim = ["sıfır", "bir", "iki"]; myArray.myMethod = function (sProperty) ( warning(arguments.length > 0 ? this : this); ); myArray.myMethod(); // "sıfır, bir, iki"yi yazdırır myArray.myMethod(1); // "bir" yazdırır setTimeout(myArray.myMethod, 1000); // 1 saniye sonra "" yazdırır setTimeout(myArray.myMethod, 1500, "1"); // 1,5 saniye sonra "tanımsız" yazdırır // "this" nesnesini .call ile geçirmek işe yaramaz // çünkü bu, setTimeout'un kendi içindeki this değerini değiştirecektir // biz myArray içindeki this değerini değiştirmek isterken .myMethod // aslında bu bir hata olacaktır çünkü setTimeout kodu bunun pencere nesnesi olmasını beklemektedir: setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: WrappedNative prototip nesnesinde geçersiz işlem" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // aynı hata

Gördüğünüz gibi eski JavaScript'te bu nesneyi geri çağırma işlevine aktarmanın bir yolu yok.

Olası bir çözüm

"Bu" sorunu çözmenin olası bir yolu, iki yerel setTimeout() veya setInterval() global fonksiyonunu iki taneyle değiştirmektir. yerli olmayan Function.prototype.call yöntemi aracılığıyla çağrılmasını sağlayanlar. Aşağıdaki örnek olası bir değişimi göstermektedir:

// "this" nesnesinin JavaScript zamanlayıcıları aracılığıyla geçişini etkinleştirin var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argümanToPass1, argümanToPass2, vb. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback exampleof Function ? function) () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay ); window.setInterval = function (vCallback, nDelay /*, argümanToPass1, argümanToPass2, vb. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback exampleof Function ? function) () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay );

Bu iki değişiklik aynı zamanda IE'deki zamanlayıcıların geri çağırma işlevlerine isteğe bağlı bağımsız değişkenlerin HTML5 standart geçişini de sağlar. Yani şu şekilde kullanılabilirler: standartlara uygun olmayan aynı zamanda çoklu dolgular. Şuna bakın: standartlara uygunçoklu doldurma

Yeni özellik testi:

Dizim = ["sıfır", "bir", "iki"]; myArray.myMethod = function (sProperty) ( warning(arguments.length > 0 ? this : this); ); setTimeout(alert, 1500, "Merhaba dünya!"); // setTimeout ve setInterval'ın standart kullanımı korunur, ancak... setTimeout.call(myArray, myArray.myMethod, 2000); // 2 saniye sonra "sıfır,bir,iki" yazdırır setTimeout.call(myArray, myArray.myMethod, 2500, 2); // 2,5 saniye sonra "iki" yazdırılır

Daha karmaşık ama yine de modüler bir versiyonu için ( Şeytan) bkz. JavaScript Daemon Yönetimi . Bu daha karmaşık versiyon, geniş ve ölçeklenebilir bir yöntem koleksiyonundan başka bir şey değildir. Şeytan yapıcı. Ancak Şeytan yapıcının kendisi bir klondan başka bir şey değildir MiniDaemon için ek bir destek ile içinde Ve başlangıç başlatılması sırasında bildirilen işlevler şeytan. Böylece MiniDaemon basit animasyonlar için önerilen yol olmaya devam ediyor çünkü Şeytan yöntem koleksiyonu olmadan aslında onun bir kopyasıdır.

minidaemon.js /*\ |*| |*| :: MiniDaemon:: |*| |*| Revizyon #2 - 26 Eylül 2014.setInterval |*| https://site/Kullanıcı:fusionchess |*| https://github.com/madmurphy/minidaemon.js |*| |*| Bu çerçeve, GNU Kısıtlı Genel Kamu Lisansı sürüm 3 veya üzeri kapsamında yayımlanmıştır. |*| http://www.gnu.org/licenses/lgpl-3.0.html |*| \*/ function MiniDaemon (oOwner, fTask, nRate, nLen) ( if (!(bu && MiniDaemon'un bu örneği)) ( return; ) if (arguments.length< 2) { throw new TypeError("MiniDaemon - not enough arguments"); } if (oOwner) { this.owner = oOwner; } this.task = fTask; if (isFinite(nRate) && nRate >0) ( this.rate = Math.floor(nRate); ) if (nLen > 0) ( this.length = Math.floor(nLen); )) MiniDaemon.prototype.owner = null; MiniDaemon.prototype.task = null; MiniDaemon.prototype.rate = 100; MiniDaemon.prototype.length = Sonsuzluk; /* Bu özellikler salt okunur olmalıdır */ MiniDaemon.prototype.SESSION = -1; MiniDaemon.prototype.INDEX = 0; MiniDaemon.prototype.PAUSED = doğru; MiniDaemon.prototype.BACKW = doğru; /* Genel yöntemler */ MiniDaemon.forceCall = işlev (oDmn) ( oDmn.INDEX += oDmn.BACKW ? -1: 1; if (oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn) .BACKW) === false || oDmn.isAtEnd()) ( oDmn.pause(); return false; ) return true); /* Örnek yöntemleri */ MiniDaemon.prototype.isAtEnd = function () ( return this.BACKW ? isFinite(this.length) && this.INDEX< 1: this.INDEX + 1 >bu.uzunluk; ); MiniDaemon.prototype.synchronize = function () ( if (this.PAUSED) ( return; ) clearInterval(this.SESSION); this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this); ); MiniDaemon.prototype.pause = function () ( clearInterval(this.SESSION); this.PAUSED = true; ); MiniDaemon.prototype.start = function (bReverse) ( var bBackw = Boolean(bReverse); if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) ( return; ) this.BACKW = bBackw; this.PAUSED = false; this.synchronize();

MiniDaemon argümanları geri çağırma işlevine iletir. Bu özelliği doğal olarak desteklemeyen tarayıcılarla üzerinde çalışmak istiyorsanız yukarıda önerilen yöntemlerden birini kullanın.

Sözdizimi

var myDaemon = yeni MiniDaemon( buNesne, geri çağırmak[ , oran [, uzunluk]]);

Açıklama Kullanım notları

setInterval() işlevi genellikle animasyonlar gibi tekrar tekrar yürütülen işlevler için bir gecikme ayarlamak amacıyla kullanılır. WindowOrWorkerGlobalScope.clearInterval() işlevini kullanarak aralığı iptal edebilirsiniz.

Fonksiyonunuzun çağrılmasını istiyorsanız bir kere Belirtilen gecikmeden sonra kullanın.

Gecikme kısıtlamaları

Aralıkların iç içe yerleştirilmesi mümkündür; yani, setInterval() geri çağrısı, ilki hala devam ediyor olsa bile başka bir aralık çalışmasını başlatmak için setInterval() öğesini çağırabilir. performansta, aralıklar beş düzeyin ötesinde iç içe yerleştirildiğinde, tarayıcı aralık için otomatik olarak 4 ms'lik bir minimum değer uygulayacaktır. SetInterval()'a derinlemesine yuvalanmış çağrılarda 4 ms'den daha az bir değer belirleme girişimleri 4 ms'ye sabitlenecektir.

Tarayıcılar bazı durumlarda aralık için daha katı minimum değerler uygulayabilir, ancak bunların yaygın olmaması gerekir. Ayrıca, geri aramaya yapılan aramalar arasında geçen gerçek sürenin, verilen gecikmeden daha uzun olabileceğini unutmayın; Örnekler için WindowOrWorkerGlobalScope.setTimeout()'ta belirtilenden daha uzun gecikmelerin nedenleri konusuna bakın.

Yürütme süresinin aralık frekansından daha kısa olduğundan emin olun

Mantığınızın yürütülmesinin aralık süresinden daha uzun sürmesi olasılığı varsa, setTimeout() işlevini kullanarak adlandırılmış bir işlevi yinelemeli olarak çağırmanız önerilir. Örneğin, uzak bir sunucuyu her 5 saniyede bir yoklamak için setInterval() kullanılıyorsa, ağ gecikmesi, yanıt vermeyen sunucu ve diğer birçok sorun, isteğin ayrılan sürede tamamlanmasını engelleyebilir. Bu nedenle, kendinizi sıralı olarak geri dönmeyen sıraya alınmış XHR istekleriyle karşı karşıya bulabilirsiniz.

Komut dosyası dillerinde programlamada, programın yürütülmesini bir süreliğine duraklatmak ve ardından çalışmaya devam etmek için periyodik olarak bir duraklama oluşturmaya ihtiyaç vardır. Örneğin VBS ve PHP betiklerinde aşağıdaki yöntemler mümkündür:

VBS: wscript.sleep 1500 (1,5 saniye durur)

PHP: uyku(10); (10 saniye durun)

Bu tür duraklamalar sırasında çalışma zamanı sistemi (PHP veya VBS) hiçbir şey yapmamak. Javascript'te benzer bir şeyi sezgisel olarak kullanmaya çalışan bir geliştirici, hoş olmayan bir şekilde şaşıracaktır. Yaygın hata Javascript'te bir duraklama oluşturmaya çalışırken şöyle görünür:

Function badtest() ( for (var i=1; i< 10; i++) { window.setTimeout("document.getElementById("test1").value += " + i, 900) } }

Döngü sırasında sıra bir sonraki sayıyı çizmeye geldiğinde, setTimeout'unuzun Javascript'in çalışmasını gerçekten durduracağını, 0,9 saniye bekleyeceğini, istenen sayıyı giriş alanının sonuna ekleyeceğini ve ardından çalışmaya devam edeceğini düşünüyorsunuz. Ancak gerçekte bu doğru değildir: Javascript'teki setInterval ve setTimeout yalnızca parantez içinde belirtilen eylemin (veya işlevin) yürütülmesini geciktirir. Örneğimizde aşağıdakiler gerçekleşecektir:

  • ben = 1;
  • "1" sayısının giriş alanına eklenmesini 0,9 saniye geciktirir;
  • Bu problemi belirledikten hemen sonra döngü şöyle devam eder: i=2;
  • "2" sayısının giriş alanına eklenmesini 0,9 saniye geciktirir;
  • Hemen, örneğin 1 ms anlamına gelir (yani, 900 ms ile karşılaştırıldığında orantısız derecede küçüktür): döngü, aynı anda birden fazla ertelenmiş görev yaratarak işini neredeyse anında yapar. Bu, bekleyen tüm "çizim" görevlerinin, yeni sayıların eklenmesi arasında duraklamalar olmadan neredeyse aynı anda tamamlanacağı anlamına gelir. Döngü başlar; her şey 0,9 saniye boyunca donuyor; ve büzgü - tüm sayılar arka arkaya vurulur.

    Böyle bir durumda setTimeout nasıl doğru şekilde uygulanır? Karmaşık. İşlevi çağırmanız gerekecek tekrarlı(fonksiyon içinden aynı fonksiyon) ve bu sürecin sonsuz olmaması için bir durdurma koşulu ayarlayın (örneğin, yazdırılacak sayının boyutu):

    Welltest() işlevi ( if (i< 9) { document.getElementById("test2").value += ++i window.setTimeout("welltest()", 400) } }

    Ve i değişkeninin fonksiyonun dışında başlatılması gerekecek - örneğin, şöyle:

    Artık her şey olması gerektiği gibi çalışıyor (gecikme süresini 0,9 saniyeden 0,4 saniyeye düşürdük). Ancak bu tür görevler için setTimeout yerine setInterval kullanmak daha mantıklıdır (ancak bu iki işlev gerektirecektir):

    Function besttest() ( window.i = 0 window.timer1 = window.setInterval("draw()", 400) ) function Draw() ( document.getElementById("test3").value += ++i if (i) >= 9) clearInterval(window.timer1)) )

    Javascirpt setInterval yönteminin özelliği "kendi kendine" geçmemesidir; özel bir clearInterval yöntemiyle durdurulması gerekir. Ve tam olarak neyin durdurulması gerektiğini netleştirmek için, ertelenen eylemin görevine özel bir tanımlayıcı atanır - bir zamanlayıcı: window.timer1 = window.setInterval(...) .

    Tanımlayıcılar ayrıca setTimeout yöntemiyle oluşturulan görevlere de atanabilir. Tüm zamanlayıcı kimlikleri birbirinden farklı olmalıdır (mevcut tarayıcı penceresinde benzersiz). Daha sonra pencerede ertelenmiş eylemleri kullanan birkaç farklı görev oluşturabilirsiniz ve bu görevler paralel olarak yürütülür (bilgisayarın yeterli kaynağı varsa, bir nevi eşzamanlı olarak), ki bu PHP veya VBS'de temelde imkansızdır.

    Burada aynı anda çalışan birkaç Javascript zamanlayıcının bulunduğu bir sayfa örneği verilmiştir: setinterval.htm (setinterval.js dosyasındaki Javascript işlevleri). Tüm sayfa zamanlayıcılar (menü hariç) Esc tuşu kullanılarak durdurulabilir. Tüm örnek zamanlayıcılar "doğal" (ve soyut i++ değil) geri sayıma (zaman veya mesafe) dayanmaktadır. Tüm “saatler” özel olarak senkronizasyon dışıdır (netlik sağlamak için). Mesafeye bağlı zamanlayıcılar "göstergede" ve açılır ("çekilir") menüde kullanılır.

    Aşağıya doğru açılan menü

    Kayar menümüz aslında kayar ("başlığın" altından): nasıl kaydığını görebilmeniz için öğeler arasında özel olarak boşluklar bırakılır. Beklenmedik bir şekilde, farklı uzunluktaki listeler için çıkışı eşit derecede pürüzsüz hale getiremediğimiz ortaya çıktı - muhtemelen bilgisayarın düşük performansı nedeniyle (AMD Athlon 999 MHz).

    Güzellik ve uyum için farklı menü öğelerinin listelerinin aynı anda ortaya çıkması gerektiği oldukça açıktır. Yani, daha uzun listeler daha yüksek bir hızda, daha kısa listeler ise daha düşük bir hızda çıkarılmalıdır. Bunun şu şekilde uygulanabileceği görülüyor:

  • Toplam “kalkış” süresini örneğin 200 ms olarak ayarladık.
  • Açılır listenin yüksekliği 20 piksel ise, onu her 10 ms'lik aralıklarla bir piksel aşağıya taşıyabileceğimiz açıktır - ve ardından 200 ms içinde tüm liste ortaya çıkacaktır.
  • Açılır liste 40 piksel yüksekliğindeyse, aynı süreye sığması için onu her 5 ms'de bir piksel aşağı taşımamız gerekir.
  • Bu mantıkla eğer açılır liste 200px yüksekliğindeyse her 1ms'de bir piksel aşağı kaydırmamız gerekiyor. Ancak bilgisayarımızda böyle bir hız çalışmıyor - tarayıcının listenin yeni konumunu bir milisaniyede çizecek zamanı yok. Evet. Javascript saymayı başarıyor (sayılacak ne var?), ancak tarayıcının (Firefox) görüntüleyecek zamanı yok. Web için tipik bir durum.

    Bu nedenle sadece koltuk değneği yardımıyla menüden çıkış süresini aşağı yukarı eşitlemek mümkün ve bunun daha fazla kişi için nasıl çalışacağı hala belirsiz. hızlı bilgisayar. Ama en yavaş olana güvenmeliyiz, değil mi? Algoritma (bilgisayarın hızını hesaba katmadan) şöyle bir şey ortaya koyuyor:

  • Listeyi kontrol etmek için toplam süreyi ayarlayın: süre = 224 (ms).
  • Döngüdeki bir aralık için minimum süreyi ayarladık: gecikme = 3 (ms).
  • Listeyi taşımak için minimum adımı ayarlayın: ofset = 1 (px).
  • Tüm bunları listenin yüksekliğine göre değiştiriyoruz: 1) gecikme (aralık) süresini yükseklikle ters orantılı ve toplam süre ile doğru orantılı olarak artırın (224 yükseklikte katsayı 1'dir); 2) Yükseklik 40 pikselden büyükse minimum adımı yükseklikle orantılı olarak artırın. En yavaş bilgisayar için "40" sabiti deneysel olarak elde edildi. Pentium 4 CPU'lu 2,53 GHz bilgisayar üzerinde yapılan testler tamamen aynı sayıyı ortaya çıkardı: 40. Aksi takdirde, zamanlayıcılar sıra dışı kalır, listeler sıra dışı kalır.
  • Artık listeler az çok çıkıyor. Aşağı yukarı benzer bir süre için. setinterval.htm sayfasında.

    Ve işte Bruce geliyor:

    Function Slide_do(obj, maxtop, offset) ( if (getTopLeft(obj).top)< maxtop) { obj.style.top = getTopLeft(obj).top + offset } else { if (obj && obj.timer1) { clearInterval(obj.timer1) obj.timer1 = null } } }

    İç içe geçmiş listeleri menünün dışına iten fonksiyonun kendisi, görebildiğimiz gibi, çok basittir. Geriye kalan tek şey onu şu satıra benzer bir şeyle çalıştırmak:

    Ts.timer1 = setInterval(function())(slide_do(ts, maxtop, offset))), gecikme)

    Başlamadan önce tüm bu maxtop ve offset değerlerini hesaplayın ve ayrıca listeyi mintop konumuna yerleştirin. 40 satırlık “ön” slayt() fonksiyonunun yaptığı da budur. Ve hepsi bir arada - setinterval.js dosyasında. Evet ve bu saçmalık, içerilen stiller dosyası olmadan hiç işe yaramaz