2016-05-13 6 views
6

Не могли бы вы объяснить мне, в чем разница между этими сценариями ниже? Первый, найденный здесь в Stack Overflow, второй - это моя собственная версия, которую я лучше понимаю, но не работает. Почему он не работает, кстати?Looping JavaScript function

1.

(function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})(); 

2.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    blink(); 
} 
blink(); 
+0

Второй бросает StackOverflow исключение. Он не должен называть себя. – Bergi

ответ

11

Первый пример представляет собой Немедленно-Вызванный Функция Выражение (IIFE). Это функция, которая сразу же выполняет свою работу после создания. IIFE - общий шаблон проектирования JavaScript, используемый большинством популярных библиотек (jQuery, Backbone.js, Modernizr и т. Д.), Чтобы поместить весь код библиотеки внутри локальной области.

В ES6 это можно переписать с помощью Arrow function если вы хотите .blinkMe мигать только один раз:

(() => $('.blinkMe').fadeOut(500).fadeIn(500))(); 

Вы можете цепи столько fadeIn и fadeOut функции, как вы хотите, конечно. Если вы хотите, чтобы он вращается бесконечно, я бы предложил путь IIFE.

Дополнительная информация о IIFE here.


О вашем втором примере. Вы вызываете функцию внутри своей собственной функции (также называемой рекурсивной петлей). В вашем случае это создает бесконечный цикл, поэтому он не работает. Удалите blink(); внутри функции, и он будет работать:

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
} 
blink(); 

Кроме того, с JavaScript вы можете решить эту проблему с CCS3 анимации. Анимации CSS3 выполняются в отдельном потоке. Это решение без JQuery:

(function blink() { 
 
    document.getElementsByClassName('blinkMe')[0].className += ' blinkActive'; 
 
})(); 
 

 
// Arrow function: 
 
//(() => document.getElementsByClassName('blinkMe')[0].className += ' blinkActive')();
.blinkMe { 
 
    width: 80px; 
 
    height: 80px; 
 
    background: deepskyblue; 
 
} 
 
.blinkActive { 
 
    -webkit-animation: blink 1s infinite; 
 
    animation: blink 1s infinite; 
 
} 
 
@-webkit-keyframes blink { 
 
    0%, 100% { opacity: 1; } 
 
    50% { opacity: 0; } 
 
} 
 
@keyframes blink { 
 
    0%, 100% { opacity: 1; } 
 
    50% { opacity: 0; } 
 
}
<div class="blinkMe"></div>

Я не знаю, сколько элементов вы хотите мигать на вашей странице, если это только один элемент, который вы можете использовать идентификаторы вместо классов. Имейте в виду, что правило @keyframes не поддерживается в IE9 или более ранних версиях и Opera Mini: Link.

+0

улучшить ... Я думаю, что это сентиментальность, «код здесь выполняется один раз в своей области», и поэтому этот шаблон обычно используется плагинами jQuery. – daremachine

+0

@daremachine Я обновил свой ответ с дополнительной информацией. – Patrick2607

+1

«В вашем случае это создает бесконечный цикл, поэтому он не работает», о бесконечном цикле это неверно. Правильные версии - это бесконечные циклы (иначе они перестанут мигать). Неверная версия представляет собой экспоненциальный цикл, поэтому он разбился. –

7

Первый - IIFE. То есть, функция сразу же вызывается (выполняется) после ее объявления. Он не привязан к глобальному объекту окна и поэтому не загрязняет его.

Вторая функция экспоненциально рекурсивна. Каждый раз, когда он запускается, он вызывает себя дважды больше, один раз в качестве обратного вызова метода jquery fadeIn и еще раз в теле функции.

6

Линия $('.blinkMe').fadeOut(500).fadeIn(500, blink); уже звонит blink при завершении. Поэтому вызов blink() похож на удвоенную функцию (и даже больше на каждый вызов). Таким образом, этот вызов был проблемой.

EDIT: Но, как я только что узнал сегодня, таймеры не выполняются в другом потоке в JavaScript.Таким образом, blink() в функции blink принимает все кадры исполнения, а обратный вызов blink никогда не вызывается, но он все еще зарегистрирован для вызова. Поскольку, я тестировал, добавляя максимальное количество итераций, которое можно было бы вызвать в пределах blink().

function blink() { 
 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
 
    //blink(); 
 
} 
 
blink();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
<span class="blinkMe">Blinking</span>

6

В этом фрагменте, поименованный функция создается, а затем сразу же выполняется один раз в Immediately-Invoked Function Expression. Имя функции доступно только для себя, поэтому ее можно снова вызвать в закрытии тела функции, в этом случае в качестве обратного вызова функции fadeIn.

(function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
})(); 


В этом фрагменте, поименованный функция создается и называется. Кроме того, функция снова вызывает себя, что создаст бесконечную рекурсию, поэтому она терпит неудачу. В отличие от последнего фрагмента, blink также будет доступен вне самого закрытия функции.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    blink(); 
} 
blink(); 

Удаление blink() вызова внутри самой функции следующим образом сделает его функционировать почти идентичен, за различные в blink объеме, за исключением.

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
} 
blink(); 
2

Это рекурсивная функция (анимация).

Согласно jQuery docs, fadeIn() принимает два аргумента: duration (в мс) и complete. Второй аргумент - это функция, которая вызывается после завершения анимации. Это может быть сама или другая функция.

Во второй функции вы вызываете blink() снова и снова ... но вторая и третья никогда не начинаются. Лучший способ - первый.

2

Ваша функция работает, но Навигатор блокирует ее из-за слишком большой рекурсии. потому что вы callling мигания() сразу после FadeIn просто попробовать,

function blink() { 
    $('.blinkMe').fadeOut(500).fadeIn(500, blink); 
    //remove this call which causes too many recursions 
    //blink(); 
} 
//then call the method 
blink();