Web Workers Nedir? Mvc ve AngularJs İle Nasıl Kullanılır?

Bugün Web Workers nedir ve gerçekten ne zaman ihtiyacımız olur sorularına Mvc ve AngularJS kullanarak yazacağımız birkaç örnek ile cevap arayacağız.

Öncelikle gelin sorunu ele alalım ve ihtiyaca yönelik çözümü bu yolda arıyalım:

Boş bir Mvc projesi Visual Studio 2015 ile yaratılır. Amaç belirlenen sayı kadar bir değişkeni saydırma ve bunu yine belirlenen sayı kadar tekrarlama olacaktır. Her bir tekrardan sonra, kaçıncı sırada olduğunu bildiren bir bildiri ekrana basılacaktır.

İstenen 2 değişkenin girileceği html input elementleri, aşağıda görüldüğü gibi default değerleri ile tanımlanmıştır. Ayrıca işlemin başlamasını sağlayan ve bir de ekrana mesaj basan 2 button konmuştur. Son olarak bildirimlerin yazılacağı “divWorkers” html elementi oluşturulmuştur.

Şimdi gelin “Sayma” işleminde çağrılacak Javascript kodunu yazalım: Aşağıdaki koda baktığımızda “5”‘defa “10milyon” kez sayım yapılacak, ve 5 seferin her birinde ekrana kaçıncı seferde olduğu bilgisi yazılacaktır. Bu koda bakılınca, dikkat edilmesi gereken şey, bu işlem sırasında başka bir işlemin yapılamıyacağıdır. Örneğin “SAYMA” buttonuna basıldıktan sonra “MESAJ” buttonuna basılır ise,ilgili alert ilk işlem bitmeden sonra karşımıza çıkmaktadır.

İsterseniz problemi daha iyi anlamak için yukarıdaki kodun devamına bir kutu koyalım. Bu kutu klavyenin yön tuşlarına basılınca hareket ettirilebilsin. Yani yukarı + aşağı + sağ ve sol. Şimdi isterseniz önce html’i oluşturalım: “square” kutusunun ve ona ait css lerin kodları aşağıda görüldüğü gibidir.

Şimdi sıra geldi kutuyu hareket ettireceğimiz Javascript kodlarına: Aşağıda görüldüğü gibi “onkeyup” ile basılan tuşun “keyCode“‘una bakılmış ve yön tuşlarından biri ise(37,38,39,40) “switch case” yapısı ile ilgili kutuya yön verilmiştir. “recursive” şekilinde kendi kendini çağıran ilgili “moveSquare()” function’ı “requestAnimationFrame()” ile çağrılarak ilgili kutunun position’ının belirlenen “MOVEMENT_STEP” değeri kadar animatif olarak değişmesi sağlanmıştır.

Önemli Not: Aşağıda görüldüğü gibi en başta kutu sağ doğru hareket ettirilmeye başlanmıştır. Tam bu esnada sayma işlemine başlanıldığında herşeyin donduğu ve kutunun hareket ettirilemediği görülmektedir. Bu durum belirlenen sayma işlemi bitene kadar devam etmekte ve ancak tüm işlem bittikten sonra kutu klavyenin yön tuşlarına cevap verebilmektedir. Aynı zamanda ekrana yazılacak bildiriler tek tek değilde, yine işlem bitiminde topluca yazılabilmektedir.

Sorunu anladığımıza göre artık çözüme geçebiliriz.

Amaç: Eğer yapılması istenen iş çok zaman alıcak bir iş ise, ilgili işlemin bitmesi donuk bir ekrandan izlenmemelidir. O anda yapılan işlemden bağımsız olarak, ekrandaki diğer işlemlere devam edilebilmelidir. Bu açıdan bakılınca ilk akla gelen thread konusu olmaktadır. İşte biz bugun javascript’in thread’i olan HTML5  ile gelen Web Workers’ı işleyeceğiz. Web worker lar  ilgili kodun, javascript ‘in üzerinde çalıştığı browser’ın kullandığı thread’in dışında, farklı başka bir thread’de çalıştırılmasını sağlarlar.  2 tipi mevcuttur.

  • Dedicated Worker  : Sadece 1 parent’a yani yaratıldığı parent’a bağlıdır.
  • Shared Worker : Aynı domaindeki  birden fazla parent veya worker’ lar ile çalışabilir. 1 tane bağlantısı kalsa bile worker thread’i sonlanmıyacaktır.

Bu iki madde de anlatılmak istenen esas konu worker’lar harici javascript dosyaları ile çalışırlar. Ya bunlardan 1 tanesi ile çalışabilirsiniz. Ya da farklı farklı birkaç javascript dosyası ile de iletişim halinde olabilirsiniz. İşte ihtiyaca göre oluşan farklılık budur.

Gelin bu kadar teoriden sonra koda geçip neler oluyor bir bakalım:

  • Öncelikle ilgili browser’ın “window.Worker”‘ı destkeleyip desteklemediği kontrol edilir.
  • aDedicatedWorker = new Worker(“Scripts/test.js?v=1”);” aDedicatedWorker adında yeni bir worker oluşturulur. Harici çalıştırılacak javascript dosyasının(“test.js“) yolu belirtilir.
  • test.js asıl sayma işleminin harici olarak yapıldığı yerdir. Aşağıda detaylıca inceleyeceğiz.
  • Kritik yerlerden birisi burası “aDedicatedWorker.onmessage()” kısaca test.js’den post edilecek paketlerin, yakalandığı yer burasıdır. Bir çeşit listenerdır. İlgili gelen data burada “event.data“‘dir. test.js’den gönderilen bildiriler burada “divWorkers” divinin innerHTML’ine basılır. Kısaca herbir seferden sonraki bildirim, test.js’den post edilip burada “onmessage()” function’ında yakalanır ve bu yakalanan mesaj “divWorkers” divin html’ine farklı bir thread’den basılır.
  • “SAYMA” button’una tıklanınca ilgili textbox’daki değerler alınıp “aDedicatedWorker.postMessage()” function’ı ile “waiter” ve “counter” şeklinde 2 parametre ile ilgili “test.js”‘e gönderilir. Burada önemli bir nokta var.
  • Not: İlgili parametreler gönderilirken, data kopyalanarak gönderilir. Yani verinin kendisi(referansı) değil oluşturulan bir kopyası taşınır. Browser’a göre farklılık gösterese de, kopylama işleminde  structured cloning algoritması kullanılmaktadır. Bu şu demektir, gönderilen parametreler parent’da değişse de, başka bir thread(test.js)’de yapılan işlemler bundan etkilenmez.
  • Bu başlatılan worker istenir ise “aDedicatedWorker.terminate();” function’ı ile iptal edilebilir. Bu işlem aşağıdaki örneğe göre “Cancel()” ile yapılabilmektedir.

test.js: Ana sayfadan bağımsız, farklı bir thread’de istenen işin yapıldığı yerdir.

  • Yine burada da parent’dan yapılan post işleminin dinlenildiği “this.onmessage = function (event)” function’ı bulunmaktadır. İlgili “event“‘de parent’dan gönderilen “Waiter” ve “Counter” değişkenleri bulunmaktadır. İlgili data bu worker’a ‘Json‘ olarak gönderilmiştir.
  • Parent’a işlemin başladığı “postMessage(‘Worker Saymaya baslıyor.’)” function’ı ile bildirilmiştir. Parent tarafında ilgili mesaj, yukarıda görüldüğü gibi gene “aDedicatedWorker.onmessage = function (event) ” function’ı ile yakalanmaktadır. Ve ana ekranda, yani parent’da “<div id=divWorkers></div>” içerisine basılmaktadır.
  • Sonraki adımda gönderilen parametreye göre, default olarak 5 defa tekrar eden ve her seferinde 1 den 10Milyon’a kadar süren bir counter yani sayaç işlemi yapılmaktadır.
  • Her 10milyon’da, yeni bir “postMessage(currentSet + ‘. set bitti.’);” post işlemi yapılmakta ve kaçıncı sırada olunulduğu bilgisi, parent’a bildirilmektedir.
  • Tüm işlem bitince “postMessage(‘Worker saymayı bitirdi.’);” ilgili post işlemi ile işlemin bittiği, parent’a haber verilmektedir.

test.js:

İlgili WebWork’ın çalışabilmesi için IIS’den yayınlanması gerekmektedir. Yukarıda görüldüğü gibi ben IIS’den 82.portdan yayımlama yaptım.

Aşağıda projenin örnek bir çalışma videosu görülmektedir. Dikkat edilirse ilgili sayma işlemi farklı bir threadde sürdürülmekte ve ana yani parent ekranda, kullanıcının tüm komutlarına cevap verebilmektedir. Böylece ilgili işlem arkada çalışırken, ekran donmamakta, kullanıcı etkileşimi normal seyirinde başka bir threadde devam etmektedir.

  • Workerlar çalıştırılma sırasında timer işlemlerini yapabilirler. Yani setInterval, clearInterval , setTimeout, clearTimeout gibi komutları kullanabilirler.
  • XMLHttpRequest nesnelerine erişebilirler. Parent’e etkilemeden sync veya async request işlemler yapabilirler.
  • Workerlar harici çalışan farklı bir thread’deki javascript olduklarından “DOM, Window, document ve parent” gibi nesnelere erişemezler.

Tüm Kod Index.cshtml: test.js’de herhangi bir değişiklik yoktur.

Peki AngularJS’ile Web Workerlar Nasıl çalışır:

Index.cshtml: AngularJs’li Mvc uygulaması IIS ortamına publish işlemi yapılmadan Web Workerların çalışması sağlanmıştır. Aşağıda görüldüğü gibi tüm değişkenler ve functionlar “$scope” altında toplanmıştır. Yine ilgili worker “$scope” altında tanımlanmıştır. Harici Javascript dosyası yine bu örnekde de “test.js”‘dir. Angular’da “window.onKeydown” yerine ayrı bir directive yazılabilirdi. Ama ben bu örnek için, esas odak noktasından uzaklaşmak istemedim. Web Workerların AngularJs altında çalışma mantığı görüldüğü gibi normal bir html sayfasından çok da farklı değildir.

test.js:

Örnek Demo (İptal): http://webworkerblock.azurewebsites.net/

Bu makalede Html5 ile gelen Web Workerları inceledik. Bir Html sayfada yüklü işlemlerin yapılması gerektiği durumlarda, yani tamamlanması vakit alan proseslerde, kullanıcı tarafında hayatın nasıl devam edebileceğini, var olan işlemlerin arkada farklı bir thread ile nasıl yönetilebileceğini, web workerlar kullanılarak başlatılan işlerin arkada çalışması esnasında, kullanıcının diğer işlerine nasıl devam edebileceğini hep beraber inceledik. Böylece geldik bir makalenin daha sonuna :)

Yeni bir makalede görüşmek üzere hoşçakalın.

Kaynak: https://html5demos.com/worker/#view-source, https://stackoverflow.com/questions/5605588/how-to-use-requestanimationframe

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

9 Cevaplar

  1. Muhammed dedi ki:

    Oldukça açıklayıcı ve faydalı bir yazı olmuş. Çalışmalarınız için teşekkür ederim.

  2. Emre dedi ki:

    Hocam konu ile alakalı değil ama ben bir web servise bağlandığım zaman eğer o web servisi aktif değilse uygulamam hiç çalışmıyor mesela web servisi aktif değilse bir mesaj göstersem bilgiler gelmiyor tarzında .
    Teşekkür ederim iyi çalışmalar dilerim :)

  3. Tayfun KOÇ dedi ki:

    Elinize sağlık hocam.

  4. Enes İnce dedi ki:

    Hocam çok açıklayıcı bir yazı olmuş elinize sağlık

Tayfun KOÇ için bir cevap yazın Cevabı iptal et

E-posta hesabınız yayımlanmayacak.