نوشتن یک تکرار کننده سفارشی در جی کوئری

 

 مسئله

فرض کنید در داخل یک آبجکت جی کوئری، چند عنصر را انتخاب کرده باشیم و بخواهیم بر روی آنها حلقه بزنیم(تکرار کنیم) و پس از هر حلقه، یک وقفه ایجاد کنیم؛ بعنوان مثال فرض کنید بخواهیم عناصری را یک به یک آشکار کنیم:

<span class="reveal">Ready? </span>
<span class="reveal">On your mark! </span>
<span class="reveal">Get set! </span>
<span class="reveal">Go!</span>

 ما می توانیم از متد each() استفاده کنیم اما عناصر به یکباره آشکار می شوند:

$('.reveal').each( function() {
   $(this).show();
});
// این کد ساده تر است:
$('.reveal').show();

 راه حل:

یک تکرار کننده ی سفارشی ایجاد کنید که از متد setTimeout() برای وقفه دادن به تابع های callback بر اساس زمان، استفاده می کند:

نکته: یک callback در حقیقت تابعی است که به صورت یک آرگومان به یک تابع دیگر داده می شود. این روش به یک تابع امکان می دهد تا یک تابع دیگر را فراخوانی کند. یک تابع callback  می تواند پس از اینکه اجرای یک تابع دیگر تمام شد، اجرا شود.

// یک تکرار کننده روی یک آرایه(معمولا یک آبجکت جی کوئری است اما می تواند
// هر آرایه ای باشد) و برای هر عنصر، یک تابع پاسخ دهنده را فرا می خواند
// و بین هر یک از فراخوانی ها، یک وقفه ی زمانی را ایجاد می کند
//همان آرگومان ها jQuery.each() تابع پاسخ دهنده، مانند یک تابع پاسخ دهنده ی عادی
// را دریافت می کند
jQuery.slowEach = function( array, interval, callback ) {
  if( ! array.length ) return;
  var i = 0;
  next();
  function next() {
    if( callback.call( array[i], i, array[i] ) !== false )
      if( ++i < array.length )
        setTimeout( next, interval );
  }
  return array;
};

// (یک آبجکت جی کوئری) this تکرار بر روی
// و فراخوانی یک تابع پاسخ دهنده برای هر عنصر به همراه یک تاخیر زمانی
// بین هریک از پاسخ دهنده ها
//  jQuery(...).each() تابع پاسخ دهنده مانند یک تابع پاسخ دهنده ی عادی
// آرگومان ها را دریافت می کند
jQuery.fn.slowEach = function( interval, callback ) {
  return jQuery.slowEach( this, interval, callback );
};

اکنون در کدهای بالایی، به جای متد .each() از متد .slowEach() استفاده کنید و به سادگی مقدار timeout (وقفه) را اضافه کنید:

// Show an element every half second
$('.reveal').slowEach( 500, function() {
  $(this).show();
});

 


توضیحات کدها

متد .each() که به جی کوئری تعلق دارد، علم موشک سازی نیست!. در حقیقت اگر ما به کدهای سازنده ی جی کوئری 1.3.2 در مورد تکرار بر روی یک آبجکت جی کوئری، نگاه کنیم، با یک حلقه ی سر راست مواجه می شویم:

jQuery.each = function( object, callback ) {
var value, i = 0, length = object.length;
  for(
      value = object[0];
      i < length && callback.call( value, i, value ) !== false;
      value = object[++i]
  ) {}

  return object;
};

این کدها را می توانیم به طریق آشنا تری کدنویسی کنیم:

jQuery.each = function( object, callback ) {
  for(
      var i = 0, length = object.length;
      i < length;
      ++i
  ) {
      var value = object[i];
      if( callback.call( value, i, value ) === false )
      break;
    }
  return object;
};

 نکته: برای فهمیدن خط شماره 8 از کدهای بالا، این مقاله را مشاهده کنید.

ما می توانیم تابع های مشابهی بنویسیم تا بر روی آرایه ها یا آبجکت های جی کوئری، به روش های مفید دیگری حلقه بزنیم(تکرار ایجاد کنیم). یک مثال مشابه با متد slowEach() که قبلا ایجاد کردیم، یک متد است که بر روی یک آبجکت جی کوئری، به صورت معکوس حلقه می زند(تکرار ایجاد می کند):

// تکرار بر روی یک آرایه یا آبجکت جی کوئری به ترتیب معکوس
jQuery.reverseEach = function( object, callback ) {
  for( var value, i = object.length; --i >= 0; ) {
      var value = object[i];
      console.log( i, value );
      if( callback.call( value, i, value ) === false )
         break;
  }
};

// یک آبجکت جی کوئری) به صورت معکوس) "this" تکرار بر روی 
jQuery.fn.reverseEach = function( callback ) {
  jQuery.reverseEach( this, callback );
  return this;
};

 این کد تلاش نمی کند تا مانند متد .each()، تمام موردها را به کار ببرد و اعمال کند. بلکه تنها، مواردی معمولی برای کد جی کوئریِ نمونه، را اعمال می کند.

 

This doesn’t attempt to handle all of the cases that .each() handles, just the ordinary
case for typical jQuery code.

 

جالب است بدانید که یک تکرار کننده ی سفارشی(iterator) به هیچ وجه نمی تواند از یک حلقه(loop) استفاده کند. متد .reverseEach() و متد استاندارد .each() هر دو از حلقه های نسبتاً معمولی استفاده می کنند؛ اما در متد .slowEach() هیچ حلقه ی صریح جاوا اسکریپتی وجود ندارد. سوال اینجاست که چرا این متد اینگونه است و چگونه می تواند بر روی عناصر، بدون داشتن یک حلقه(loop)، حلقه بزند؟ جاوا اسکریپت در یک مرورگر وب، از تابع sleep() برخوردار نیست؛ اما در بیشتر زبان ها، این تابع پیدا می شود.

برای وقفه دادن به اجرای اسکریپت، راهی وجود ندارد؛ مثلا نمی توانیم به صورت زیر عمل کنیم:

doSomething();
sleep( 1000 );
doSomethingLater();

 به جای آن، مانند هر فعالیت غیر هم زمان(asynchronous activity) در جاوا اسکریپت، تابع setTimeout() یک callback دریافت می کند که وقتی که فاصله ی زمانی(interval) سپری شود، فراخوانی شود.

شماره 5

متد slowEach() ، متغیر حلقه، یعنی متغیر i را در callback تابعِ setTimeout() با استفاده از یک کلوژر(closure) افرایش می دهد؛ تا از مقدار آن متغیر، بین تکرارها محافظت کند. ( برای اطلاعات بیشتر در مورد کلوژر ها به اینجا مراجعه کنید).  مانند متد .each()، متد .slowEach() نیز مستقیماً بر روی یک آبجکت جی کوئری یا یک آرایه که به آن می دهیم، اجرا می شود. بنابراین هر تغییری که ما در آن آرایه، قبل از اینکه تکرار آن پایان یابد، انجام دهیم، بر روی تکرار(iteration) تاثیر می گذارد.

 برخلاف متد .each()، متد .slowEach() غیر همزمان(asynchronous) است( یعنی فراخوانی تابع callback پس از اینکه متد .slowEach() عمل return انجام دهد، اعمال می شوند)؛ بنابراین اگر ما آبجکت جی کوئری یا عناصر آن را پس از اینکه متد slowEach() به return برسد، تغییر دهیم، و این کار قبل از تمام callback ها انجام شود، می تواند بر روی تکرار(iteration) تاثیر بگذارد.

نوشتن دیدگاه

لطفا نظرات خود را بیان کنید. به سوالات در سریع ترین زمان پاسخ داده خواهد شد.اما به نکات زیر توجه کنید:
1. سعی کنید نظرات شما مرتبط با مقاله ی مورد نظر باشد، در غیر این صورت پاسخ داده نخواهد شد.
2. سوالات خود را به صورت کوتاه بیان کنید و از پرسیدن چند سوال به طور همزمان خودداری کنید.
3. سوال خود را به طور واضح بیان کنید و از کلمات مبهم استفاده نکنید.


تصویر امنیتی
تصویر امنیتی جدید

ستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعالستاره غیر فعال