اشتراک‌ها
کتابخانه sammy

Sammy is a tiny JavaScript framework built on top of jQuery, It's RESTful Evented JavaScript.

کتابخانه sammy
اشتراک‌ها
LINQ در JavaScript

Mastering the Arcane Art of JavaScript-Mancy for C# Developers - Chapter 7: Using LINQ in JavaScript

LINQ در JavaScript
مطالب
بررسی استراتژی‌های تشخیص تغییرات در برنامه‌های Angular
وقتی تغییری را در اشیاء خود به وجود می‌آورید، Angular بلافاصله متوجه آن‌ها شده و viewها را به روز رسانی می‌کند. هدف از این مکانیزم، اطمینان حاصل کردن از همگام بودن اشیاء مدل‌ها و viewها هستند. آگاهی از نحوه‌ی انجام این عملیات، کمک شایانی را به بالابردن کارآیی یک برنامه‌ی با رابط کاربری پیچیده‌ای می‌کند. یک شیء مدل در Angular عموما به سه طریق تغییر می‌کند:
- بروز رخ‌دادهای DOM مانند کلیک
- صدور درخواست‌های Ajax ایی
- استفاده از تایمرها (setTimer, setInterval)


ردیاب‌های تغییرات در Angular

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


این پیمایش ترتیبی از بالا به پایین، از این جهت صورت می‌گیرد که اطلاعات کامپوننت‌ها از والدین آن‌ها تامین می‌شوند. تشخیص دهنده‌های تغییرات، روشی را جهت ردیابی وضعیت پیشین و فعلی یک کامپوننت ارائه می‌دهد تا Angular بتواند تغییرات رخ‌داده را منعکس کند. اگر Angular گزارش تغییری را از یک تشخیص دهنده‌ی تغییر دریافت کند، کامپوننت مرتبط را مجددا ترسیم کرده و DOM را به روز رسانی می‌کند.


استراتژی‌های تشخیص تغییرات در Angular

برای درک نحوه‌ی عملکرد سیستم تشخیص تغییرات نیاز است با مفهوم value types و reference types در JavaScript آشنا شویم. در JavaScript نوع‌های زیر value type هستند:
• Boolean
• Null
• Undefined
• Number
• String
و نوع‌های زیر Reference type محسوب می‌شوند:
• Arrays
• Objects
• Functions
مهم‌ترین تفاوت بین این دو نوع، این است که برای دریافت مقدار یک value type فقط کافی است از stack memory کوئری بگیریم. اما برای دریافت مقادیر reference types باید ابتدا در جهت یافتن شماره ارجاع آن، از stack memory کوئری گرفته و سپس بر اساس این شماره ارجاع، اصل مقدار آن‌را در heap memory پیدا کنیم.
این دو تفاوت را می‌توان در شکل زیر بهتر مشاهده کرد:



استراتژی Default یا پیش‌فرض تشخیص تغییرات در Angular

همانطور که پیشتر نیز عنوان شد، Angular تغییرات یک شیء مدل را در جهت تشخیص تغییرات و انعکاس آن‌ها به View برنامه، ردیابی می‌کند. در این حالت هر تغییری بین حالت فعلی و پیشین یک شیء مدل برای این منظور بررسی می‌گردد. در اینجا Angular این سؤال را مطرح می‌کند: آیا مقداری در این مدل تغییر یافته‌است؟
اما برای یک reference type می‌توان سؤالات بهتری را مطرح کرد که بهینه‌تر و سریعتر باشند. اینجاست که استراتژی OnPush تشخیص تغییرات مطرح می‌شود.


استراتژی OnPush تشخیص تغییرات در Angular

ایده اصلی استراتژی OnPush تشخیص تغییرات در Angular در immutable فرض کردن reference types نهفته‌است. در این حالت هر تغییری در شیء مدل، سبب ایجاد یک ارجاع جدید به آن در stack memory می‌شود. به این ترتیب می‌توان تشخیص تغییرات بسیار سریعتری را شاهد بود. چون دیگر در اینجا نیازی نیست تمام مقادیر یک شیء را مدام تحت نظر قرار داد. همینقدر که ارجاع آن در stack memory تغییر کند، یعنی مقادیر این شیء در heap memory تغییر یافته‌اند.
در این حالت Angular دو سؤال را مطرح می‌کند: آیا ارجاع به یک reference type در stack memory تغییر یافته‌است؟ اگر بله، آیا مقادیر آن در heap memory تغییر کرده‌اند؟ برای مثال جهت بررسی تغییرات یک آرایه‌ی با 30 عضو، دیگر در ابتدای کار نیازی نیست تا هر 30 عضو آن بررسی شوند (برخلاف حالت پیش‌فرض بررسی تغییرات). در حالت استراتژی OnPush، ابتدا مقدار ارجاع این آرایه در stack memory بررسی می‌شود. اگر تغییری در آن صورت گرفته بود، به معنای تغییری در اعضای آرایه‌است.
استراتژی OnPush در یک کامپوننت به نحو ذیل فعال و انتخاب می‌شود و مقدار پیش‌فرض آن ChangeDetectionStrategy.Default است:
 import {ChangeDetectionStrategy, Component} from '@angular/core';
@Component({
  // ...
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPushComponent {
  // ...
}
استراتژی OnPush تغییرات یک کامپوننت را در حالت‌های ذیل نیز ردیابی می‌کند:
- اگر مقدار یک خاصیت از نوع Input@ تغییر کند.
- اگر یک event handler رخ‌دادی را صادر کند.
- اگر سیستم ردیابی به صورت دستی فراخوانی شود.
- اگر سیستم ردیاب تغییرات child component آن، اجرا شود.


نوع‌های ارجاعی Immutable

همانطور که عنوان شد، شرط کار کردن استراتژی OnPush، داشتن نوع‌های ارجاعی immutable است. اما نوع ارجاعی immutable چیست؟
Immutable بودن به زبان ساده به این معنا است که ما هیچگاه جهت تغییر مقدار خاصیتی در یک شیء، آن خاصیت را مستقیما مقدار دهی نمی‌کنیم؛ بلکه کل شیء را مجددا مقدار دهی می‌کنیم.
برای نمونه در مثال زیر، خاصیت foo شیء before مستقیما مقدار دهی شده‌است:
static mutable() {
  var before = {foo: "bar"};
  var current = before;
  current.foo = "hello";
  console.log(before === current);
  // => true
}
اما اگر بخواهیم با آن به صورت Immutable «رفتار» کنیم، کل این شیء را جهت اعمال تغییرات، مقدار دهی مجدد خواهیم کرد:
static immutable() {
  var before = {foo: "bar"};
  var current = before;
  current = {foo: "hello"};
  console.log(before === current);
  // => false
}
البته باید دقت داشت در هر دو مثال، شیء‌های ایجاد شده در اصل mutable هستند؛ اما در مثال دوم، با این شیء به صورت immutable «رفتار» شده‌است و صرفا «تظاهر» به رفتار immutable با یک شیء ارجاعی صورت گرفته‌است.


معرفی کتابخانه‌ی Immutable.js

جهت ایجاد اشیاء واقعی immutable کتابخانه‌ی Immutable.js توسط Facebook ایجاد شده‌است و برای کار با استراتژی تشخیص تغییرات OnPush در Angular بسیار مناسب است.
برای نصب آن دستور ذیل  را صادر نمائید:
npm install immutable --save
یک نمونه مثال از کاربرد ساختارهای داده‌ی List و Map آن برای کار با آرایه‌ها و اشیاء:
import {Map, List} from 'immutable';

var foobar = {foo: "bar"};
var immutableFoobar = Map(foobar);
console.log(immutableFooter.get("foo"));
// => bar

var helloWorld = ["Hello", "World!"];
var immutableHelloWorld = List(helloWorld);
console.log(immutableHelloWorld.first());
// => Hello
console.log(immutableHelloWorld.last());
// => World!
helloWorld.push("Hello Mars!");
console.log(immutableHelloWorld.last());
// => Hello Mars!


تغییر ارجاع به یک شیء با استفاده از spread properties

const user = {
  name: 'Max',
  age: 30
}
user.age = 31
در این مثال تنها خاصیت age شیء user به روز رسانی می‌شود. بنابراین ارجاع به این شیء تغییر نخواهد کرد و اگر از روش changeDetection: ChangeDetectionStrategy.OnPush استفاده کنیم، رابط کاربری برنامه به روز رسانی نخواهد شد و این تغییر صرفا با بررسی عمیق تک تک خواص این شیء با وضعیت قبلی آن قابل تشخیص است (یا همان حالت پیش فرض بررسی تغییرات در Angular و نه حالت OnPush).
اگر علاقمند به استفاده‌ی از یک کتابخانه‌ی اضافی مانند Immutable.js در کدهای خود نباشید، روش دیگری نیز برای تغییر ارجاع به یک شیء وجود دارد:
const user = {
  name: 'Max',
  age: 30
}
const modifiedUser = { ...user, age: 31 }
در اینجا با استفاده از spread properties یک شیء کاملا جدید ایجاد شده‌است و ارجاع به آن با ارجاع به شیء user یکی نیست.

نمونه‌ی دیگر آن در حین کار با متد push یک آرایه‌است:
export class AppComponent {
  foods = ['Bacon', 'Lettuce', 'Tomatoes'];
 
  addFood(food) {
    this.foods.push(food);
  }
}
متد push، بدون تغییر ارجاعی به آرایه‌ی اصلی، عضوی را به آن آرایه اضافه می‌کند. بنابراین اعضای اضافه شده‌ی به آن نیز توسط استراتژی OnPush قابل تشخیص نیستند. اما اگر بجای متد push از spread operator استفاده کنیم:
addFood(food) {
  this.foods = [...this.foods, food];
}
اینبار this.food به یک شیء کاملا جدید اشاره می‌کند که ارجاع به آن، با ارجاع به شیء this.food قبلی یکی نیست. بنابراین استراتژی OnPush قابلیت تشخیص تغییرات آن‌را دارد.


آگاه سازی دستی موتور تشخیص تغییرات Angular در حالت استفاده‌ی از استراتژی OnPush

تا اینجا دریافتیم که استراتژی OnPush تنها به تغییرات ارجاعات به اشیاء پاسخ می‌دهد و به نحوی باید این ارجاع را با هر به روز رسانی تغییر داد. اما روش دیگری نیز برای وادار کردن این سیستم به تغییر وجود دارد:
 import { Component,  Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
 
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
  @Input() data: string[];
 
  constructor(private cd: ChangeDetectorRef) {}
 
  refresh() {
      this.cd.detectChanges();
  }
}
در این کامپوننت از استراتژی OnPush استفاده شده‌است. در اینجا می‌توان همانند قبل با اشیاء و آرایه‌های موجود کار کرد (بدون اینکه ارجاعات به آن‌ها را تغییر دهیم و یا آن‌ها را immutable کنیم) و در پایان کار، متد detectChanges سرویس ChangeDetectorRef را به صورت دستی فراخوانی کرد تا Angular کار رندر مجدد view این کامپوننت را بر اساس تغییرات آن انجام دهد (کل کامپوننت به عنوان یک کامپوننت تغییر کرده به سیستم ردیابی تغییرات معرفی می‌شود).


کار با Observables در حالت استفاده‌ی از استراتژی OnPush

مطلب «صدور رخدادها از سرویس‌ها به کامپوننت‌ها در برنامه‌های Angular» را در نظر بگیرید. Observables نیز ما را از تغییرات رخ‌داده آگاه می‌کنند؛ اما برخلاف immutable objects با هر تغییری که رخ می‌دهد، ارجاع به آن‌ها تغییری نمی‌کند. آن‌ها تنها رخ‌دادی را به مشترکین، جهت اطلاع رسانی از تغییرات صادر می‌کنند.
بنابراین اگر از Observables و استراتژی OnPush استفاده کنیم، چون ارجاع به آن‌ها تغییری نمی‌کند، رخ‌دادهای صادر شده‌ی توسط آن‌ها ردیابی نخواهند شد. برای رفع این مشکل، امکان علامتگذاری رخ‌دادهای Observables به تغییر کرده پیش‌بینی شده‌است.
در اینجا کامپوننتی را داریم که قابلیت صدور رخ‌دادها را از طریق یک BehaviorSubject دارد:
 import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 
@Component({ ... })
export class AppComponent {
  foods = new BehaviorSubject(['Bacon', 'Letuce', 'Tomatoes']);
 
  addFood(food) {
     this.foods.next(food);
  }
}
و کامپوننت دیگری توسط خاصیت ورودی data از نوع Observable در متد ngOnInit، مشترک آن خواهد شد:
 import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
 
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
  @Input() data: Observable<any>;
  foods: string[] = [];
 
  constructor(private cd: ChangeDetectorRef) {}
 
  ngOnInit() {
     this.data.subscribe(food => {
        this.foods = [...this.foods, ...food];
     });
  }
در این حالت چون از ChangeDetectionStrategy.OnPush استفاده می‌شود و ارجاع به this.data این observable با هر بار صدور رخ‌دادی توسط آن، تغییر نمی‌کند، سیستم ردیابی تغییرات آن‌را به عنوان تغییر کرده درنظر نمی‌گیرد. برای رفع این مشکل تنها کافی است رخ‌دادگردان آن‌را با متد markForCheck علامتگذاری کنیم:
ngOnInit() {
  this.data.subscribe(food => {
      this.foods = [...this.foods, ...food];
      this.cd.markForCheck(); // marks path
   });
}
markForCheck به Angular اعلام می‌کند که این مسیر ویژه را در بررسی بعدی سیستم ردیابی تغییرات لحاظ کن.
اشتراک‌ها
پروژه WebApiProxy

هنگام استفاده از web service یا wcf کلاس‌های proxy فراخوانی سرویس‌ها با استفاده از metadata سرویس تولید می‌شد. بنابراین کار خیلی راحت بود. اما برای webapi قضیه چنین نیست... این پروژه یک بخش سمت سروری دارد که و یک کتابخانه کلاینتی. سمت سرور یک سرویس متادیتا برای تمامی api‌ها ایجاد می‌کند و سمت کلاینت با متصل شدن به آن تمامی کلاس‌های مربوطه را generate می‌کند. این عمل ایضا در سطح javascript هم انجام میشود. مزیت فوق العاده ای است.

پروژه WebApiProxy
اشتراک‌ها
دریافت کتاب TDD در جاوا اسکریپت با Jasmine
شاید شما نیز پیش گویی اخیر آقای Ian Sommerville در مورد اینکه تا سال 2022 امکان کار به عنوان یک برنامه نویس بدون مهارت‌های TDD امکان پذیر نخواد بود را نیز شنیده باشید ! در این پست قصد داریم شما را با کتابی که راهنمای خوبی در هدف آموزش این موضوع در دنیای Javascript است آشنا کنیم ، همه‌ی ما قطعا کد هایی که نوشته ایم را به صورت ساده و ... تست کرده ایم ولی در این کتاب قصد نویسنده آشنایی شما با Jasmine و انجام TDD در جاواسکریپت می‌باشد 
دریافت کتاب TDD در جاوا اسکریپت با Jasmine
نظرات مطالب
پیاده سازی Unobtrusive Ajax در ASP.NET Core 1.0
- این روش با مدل‌های تو در تو هم کار می‌کند. یک مثال: viewModel ، View و همچنین اکشن متد مرتبط
- این روش برای شما مناسب نیست؟ خودتان مستقیما متد Ajax جی‌کوئری یا حتی متد fetch توکار مرورگرها را فراخوانی کنید:
نظرات مطالب
ASP.NET MVC #21
$.validator.unobtrusive.parse باید در جایی فراخوانی شود که کار load اولیه را انجام داده:
@Ajax.ActionLink("Test",
                 "action",
                 new AjaxOptions { HttpMethod = "POST", 
                                   InsertionMode = InsertionMode.Replace, 
                                   UpdateTargetId = "UserDiv", 
                                   OnSuccess="$.validator.unobtrusive.parse('#my_form_id');"  
                                 }
                )
 اگر این کد را در partial view ایی که قرار است load شود قرار دادید، در آنجا فقط بنویسید:
<script type="text/javascript">
    $.validator.unobtrusive.parse("#my_frm_id");
</script>
نظرات مطالب
بررسی مشکلات AngularJS 1.x
سلام
بنده هم بیش از 2 سال است که با Angular کار می‌کنم  مشکلاتی که از نظر من بیشتر مهمه و باید اول پروژه  قبل از انتخاب، در نظر گرفته شود شامل موارد زیر هستش
  • وضعیت Angular (و فکر می‌کنم بقیه SPA ها) در کامپوننت‌ها خیلی بد و شما در خیلی موارد انتخاب ندارید و از کامپوننت‌های pure javascript و جی کوئری هم بیشتر مواقع نمیشه استفاده کرد و تنها یک راه اینه که خودتون کامپوننت‌های مورد نیاز خودتونو بنویسید که اینم  با توجه به Resource و زمان پروژه خیلی جاها امکان پذیر نیست. کامپوننت هایی که با Angular پیاده شده اند اکثرا یا از لحاظ Performance واقعا افتضاح هستند مثل Kendo یا خیلی ساده هستند که جوابگو نیستن و بازم مجبورید که به سمت پیاده سازی کامپوننت برید.
  • بحث Performance هم در صورتی که با یک پروژه سنگین روبرو باشید مطمئنا اذیت خواهد کرد و خیلی جاها مجبورید به سمت Pure javascript حرکت کنید و همیشه باید حواستون به watch ها، Bind‌ها و ... باشه(dirty watch) تو بحث Performance هم اگر بخوایید از Pattern‌های خاصی استفاده کنید (Flux) تا حدودی نسبت به pure javascript دستتون بسته است و باید خیلی چیزها را خودتون طراحی و پیاده سازی کنید.
  • مشکل سوم هم لود اولیه صفحتونه که می‌تونه مشکل ساز بشه
البته من فکر می‌کنم این موارد در همه SPA‌ها تقریبا موجود هستش و باید سیر تکاملی خودشونو طی کنن 
نظرات مطالب
مخفی کردن کوئری استرینگ‌ها در ASP.NET MVC توسط امکانات Routing
- بحث مطلب جاری در مورد ASP.NET MVC است و ساز و کار استاندارد آن؛ نه در مورد وب فرم‌ها یا روش‌های سفارشی دیگر. هنگام تعریف مسیر اسکریپت‌ها در MVC اگر از Url.Content و ~ برای ذکر ریشه سایت، استفاده شده باشد، موتور توکار MVC مسیرها را به صورت خودکار اصلاح می‌کند. مثلا:
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
- پیشتر در مورد دیباگ اسکریپت‌های یک سایت مطلبی تهیه شده بود: (^)

الان مرورگر، مسیر اسکریپت‌های شما را از انتهای مسیر یک مطلب دریافت می‌کند نه از ریشه سایت. برای وب فرم‌ها هم روش ذیل وجود دارد:
<script language="javascript" src='<%=ResolveUrl("~/App_Themes/MainTheme/jquery.js")%>' type='text/javascript'></script>
البته در این حالت هدر صفحه باید runat server داشته باشد:
<head runat="server">
و یا از اسکریپت منیجر استفاده کنید:
<asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Path="~/js/somefile.js" />
        </Scripts>
</asp:ScriptManager>
مطالب
نکته ای برای استفاده راحت تر ECMA Scripts در توسعه تحت شیرپوینت
هنگام کدنویسی زبان‌های سمت کاربر (Client Side)  اگر به عنوان برنامه نویس و توسعه دهنده ، با کتابخانه‌های آن آشنا 
باشید و آنها را حفظ باشید خیلی خوب است ولی اگر همین کتابخانه‌ها و توابع به ابعاد شیرپوینت گسترش یابد چه؟ مسلما حفظ کردن تمام آنها کار دشواری است ؛ راه حلی که در اینجا ارائه می‌شود ،بار گذاری این توابع در Intellisense  ویژوال استودیو است . برای این کار در صورتی که در حال نوشتن Visual WebPart هستید ، می‌توانیدبه روش زیر عمل کنید :  

ابتدا بالای صفحه مورد نظر کد زیر را وارد کنید : 
<% #if SOME_UNDEFINED_CONSTANT %>
 <script type="text/javascript" src="/_layouts/MicrosoftAjax.js" ></script>
 <script type="text/javascript" src="/_layouts/SP.debug.js"></script>
<% #endif %>
در این لحظه ویژوال استودیو آغاز به روز رسانی متادیتای Intellisense  خود می‌کند که می‌توانید این پیغام را در زیر نوار وضعیت این برنامه مشاهده کنید . 



حال می‌توانید به راحتی از این امکانات لذت ببرید و به توسعه خود سرعت دهید.