Dondurma Dükkanı Uygulamasıyla JavaScript’te Callback, Promise, ve Async/Await Kullanımı

Teo
FullStack Programming
13 min readMar 24, 2023

freeCodeCamp’te yayınlanan JavaScript Async/Await Tutorial — Learn Callbacks, Promises, and Async/Await in JS by Making Ice Cream makalesinin sadeleştirilmiş bir türkçe çevirisidir.

Photo by Miriam G on Unsplash

Bugün bir dondurma dükkanı uygulaması oluşturacağız ve aynı zamanda asenkron JavaScript’i öğreneceğiz.

İşte bu makalede ele alacağımız konu başlıkları:

  • Senkron vs Asenkron JavaScript
  • JavaScript’te Callback’ler nasıl çalışır?
  • JavaScript’te Promise’ler nasıl çalışır?
  • JavaScript’te Async/Await nasıl çalışır?

Öyleyse başlayalım!

Senkron vs Asenkron JavaScript

Senkron Sistem Nedir?

Senkron bir sistemde, görevler birbiri ardına tamamlanır.

Bunu, 10 görevi tamamlamak için sadece bir eliniz varmış gibi düşünün. Yani her seferinde bir görev tamamlamanız gerekiyor.

JavaScript varsayılan olarak senkrondur. [single threaded]. Şöyle düşünün — bir iş parçacığı (one thread), bir şeyler yapmak için bir el anlamına gelir.

Asenkron Sistem nedir?

Bu sistemde görevler bağımsız olarak tamamlanır.

Burada, 10 göreviniz için 10 eliniz olduğunu hayal edin. Böylece her el, her görevi bağımsız olarak ve aynı zamanda yapabilir.

Senkron vs Asenkron JavaScript’i Özetlemek İçin:

Üç resim, bir maratonda olduğunda:

  • Senkron sistem, üç resim aynı şeritte. Biri diğerini geçemez. Yarış birer birer bitiyor. 2 numaralı resim durursa, takip eden resim durur.
  • Asenkron sistem, üç resim farklı şeritlerde. Yarışı, kendi hızlarında bitirecekler. Kimse kimse için durmaz:

Senkron and Asenkron Kod Örnekleri

Projemize başlamadan önce bazı örneklere bakalım ve tüm şüpheleri ortadan kaldıralım.

Senkron Kod Örneği

Senkron bir sistemi test etmek için JavaScript’te şu kodu yazın:

console.log("I") // I
console.log("eat") // eat
console.log("Ice Cream") // Ice Cream

Asenkron Kod Örneği

Diyelim ki biraz dondurma yemek iki saniye sürüyor. Şimdi asenkron bir sistemi test edelim. Aşağıdaki kodu JavaScript ile yazın.

console.log("I")

// Bu kod 2 saniye sonra gösterilecek.

setTimeout(() => {
console.log("eat")
}, 2000)

console.log("Ice Cream")

// I
// Ice Cream
// eat

Senkron ve asenkron işlemler arasındaki farkı bildiğinize göre, dondurma dükkanı uygulamamızı yapalım.

JavaScript’te Callback’ler Nedir?

Bir fonksiyonu, bir argüman olarak başka bir fonksiyon içine yerleştirdiğinizde buna callback denir.

Neden callback’leri kullanıyoruz?

Karmaşık bir görevi yerine getirirken, bu görevi daha küçük adımlara böleriz. Bu adımlar arasında zamana (isteğe bağlı) ve sıraya göre bir ilişki kurmamıza yardımcı olması için callback’leri kullanırız.

Bu örneğe bir göz atın:👇

Tablo dondurma yapma adımlarını içerir.

Bunlar, dondurma yapmanız için atmanız gereken küçük adımlar. Ayrıca bu örnekte, adımların sırasının ve zamanın çok önemli olduğunu unutmayın. Meyveyi öylece doğrayıp dondurma servis edemezsiniz.

Aynı zamanda bir önceki adım tamamlanmadıysa bir sonraki adıma geçemiyoruz.

Bunu daha detaylı anlatmak için, hemen işimize başlayalım.

Fakat Bekle…

Dükkanın iki bölümü olacak:

  • Depo tüm malzemelere sahip olacak [Backend]
  • Mutfağımızda dondurma üreteceğiz [Frontend]

Verilerimizi saklayalım

Şimdi, malzemelerimizi bir object içinde saklayacağız.

Malzemeleri şu şekilde object’lerin içinde saklayabilirsiniz: 👇

let stocks = {
Fruits: ["strawberry", "grapes", "banana", "apple"]
}

Diğer malzemelerimiz burada: 👇

Diğer malzemeleri şu şekilde JavaScript object’lerinde saklayabilirsiniz: 👇

let stocks = {
Fruits: ["strawberry", "grapes", "banana", "apple"],
liquid: ["water", "ice"],
holder: ["cone", "cup", "stick"],
toppings: ["chocolate", "peanuts"]
}

Tüm iş, bir müşterinin sipariş ettiği şeye bağlıdır. Şiparişimiz geldikten sonra üretime başlıyoruz ve ardından dondurma servis ediyoruz. Öyleyse, iki fonksiyon oluşturacağız →

  • order
  • production

Her şey şu şekilde çalışıyor: 👇

Müşteriden bir sipariş alın, malzemeleri getirin, üretime başlayın ve servis yapın.

Fonksiyonlarımızı yazalım. Burada arrow fonksiyonlarını kullanacağız:

let order = () => {}

let production = () => {}

Şimdi, bu iki fonksiyon arasında şöyle bir callback kullanarak bir ilişki kuralım: 👇

let order = (call_production) => {
call_production()
}

let production = () => {}

Küçük bir test yapalım

İki fonksiyon arasındaki ilişkiyi nasıl kurduğumuza ilişkin şüphelerimizi gidermek üzere testler yapmak için console.log() fonksiyonunu kullanacağız.

let order = (call_production) => {
console.log("Order placed. Please call production")

// fonksiyon çağrılıyor 👇
call_production()
}

let production = () => {
console.log("Production has started")
}

console.log’u temizleyin

Bu kodu saklayın ve her şeyi kaldırın [stocks değişkenimizi silmeyin]. İlk fonksiyonumuzda, [Fruit name] siparişimizi alabilmemiz için başka bir argüman iletin.

// Fonksiyon 1
let order = (fruit_name, call_production) => {
call_production()
}

// Fonksiyon 2
let production = () => {}

// Tetikleyici 👇
order("", production)

İşte adımlarımız ve her adımın yürütülmesi için gereken süre.

Tablo dondurma yapma adımlarını içerir.

Bu grafikte, 1. adımın 2 saniye süren sipariş vermek olduğunu görebilirsiniz. Ardından 2. adım meyveyi keser (2 saniye), 3. adım su ve buz ekleyin (1 saniye), 4. adım makineyi çalıştırın (1 saniye), 5. adım kabı seçin (2 saniye), 6. adım sosları seçin (3 saniye) ve son adım olan 7. adım, 2 saniye süren dondurmayı servis etmektir.

Zamanlamayı belirlemek için, setTimeout() fonksiyonu mükemmeldir, çünkü aynı zamanda bir fonksiyonu argüman alarak bir callback olarak kullanır.

setTimeout() fonksiyonunun sözdizimi

Şimdi meyvemizi seçelim ve bu fonksiyonu kullanalım:

let stocks = {
Fruits: ["strawberry", "grapes", "banana", "apple"],
liquid: ["water", "ice"],
holder: ["cone", "cup", "stick"],
toppings: ["chocolate", "peanuts"]
}

// 1. Fonksiyon
let order = (fruit_name, call_production) => {
setTimeout(function () {
console.log(`${stocks.Fruits[fruit_name]} was selected`)

// Order placed. Call production to start
call_production()
}, 2000)
}

// 2. Fonksiyon
let production = () => {
// şimdilik boş
}

// Tetikleyici 👇
order(0, production)

// strawberry was selected

Sonucun 2 saniye sonra görüntülendiğini unutmayın.

Stock değişkenimizden çileği nasıl seçtiğimizi merak ediyorsanız, işte kod formatı 👇

Hİçbir şeyi silmeyin. Şimdi aşağıdaki kod ile production fonksiyonumuzu yazmaya başlayacağız. 👇

let production = () => {
setTimeout(() => {
console.log("production has started")
}, 0000)
}

İşte sonuç 👇

// strawberry was selected
// production has started

Meyveyi doğramak için mevcut setTimeout fonksiyonumuzun için başka bir setTimeout fonksiyonu yerleştireceğiz: 👇

let production = () => {
setTimeout(() => {
console.log("production has started")

setTimeout(() => {
console.log("The fruit has been chopped")
}, 2000)
}, 0000)
}

Ve işte sonuç 👇

// strawberry was selected
// production has started
// The fruit has been chopped

Hatırlarsanız, işte adımlarımız:

Bir fonksiyonu başka bir fonksiyonun içine yerleştirerek dondurma üretimimizi tamamlayalım — bu aynı zamanda callback olarakta bilinir, hatırladınız mı?

let production = () => {
setTimeout(() => {
console.log("production has started")
setTimeout(() => {
console.log("The fruit has been chopped")
setTimeout(() => {
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} Added`)
setTimeout(() => {
console.log("start the machine")
setTimeout(() => {
console.log(`Ice cream placed on ${stocks.holder[1]}`)
setTimeout(() => {
console.log(`${stocks.toppings[0]} as toppings`)
setTimeout(() => {
console.log("serve Ice cream")
}, 2000)
}, 3000)
}, 2000)
}, 1000)
}, 1000)
}, 2000)
}, 0000)
}

Ve işte konsoldaki sonuç 👇

// strawberry was selected
// production has started
// The fruit has been chopped
// water and ice Added
// start the machine
// Ice cream placed on cup
// chocolate as toppings
// serve Ice cream

Kafanız mı karıştı?

Buna callback hell denir. Şuna benzer: 👇

Callback hell gösterimi

Callback Hell’den Kaçmak için Promise’ler Nasıl Kullanılır?

Callback hell problemini çözmek ve görevlerimizi daha iyi halletmek için promise’ler icat edildi.

Promise gösterimi

Promise’leri birlikte inceleyelim.

Promise’in yaşam döngüsü

Yukarıdaki çizelgelerin gösterdiği gibi, bir promise’in 3 durumu vardır:

  • Pending: Bu başlangıç aşamasıdır. Burada hiçbir şey olmuyor. Şöyle düşünün, müşteriniz size sipariş vermek için zaman harcıyor. Ama henüz hiçbir şey sipariş etmediler.
  • Resolved: Bu, müşterinizin yemeğini aldığı ve mutlu olduğu anlamına gelir.
  • Rejected: Bu, müşterinizin siparişini almadığı ve restaurant’tan ayrıldığı anlamına gelir.

Promise’leri dondurma üretimi durumumuza uyarlayalım.

Fakat bekle…

Önce 4 şeyi daha anlamamız gerekiyor ->

  • Zaman ve iş arasındaki ilişki
  • Promise chaining
  • Error handling
  • .finally handler

Dondurma dükkanımıza başlayalım ve bebek adımlarını atarak bu kavramların her birini tek tek anlayalım.

Zaman ve iş arasındaki ilişki

JavaScript’te bir değişken oluşturalım: 👇

let is_shop_open = true

Şimdi order adlı bir fonksiyon oluşturalım daha sonra ise time ve work adlı argümanları bildirelim:

Şimdi, müşterimize “Size dondurma servis edeceğiz” sözü vereceğiz. Bunun gibi ->

let order = (time, work) => {
return new Promise((resolve, reject) => {})
}

Promise’in 2 kısmı var:

  • Resolved [ dondurma teslim edildi ]
  • Rejected [ müşteri dondurma almadı ]
let order = (time, work) => {
return new Promise((resolve, reject) => {
if (is_shop_open) {
resolve()
} else {
reject(console.log("Our shop is closed"))
}
})
}

Zaman ve iş faktörlerini if deyimimizin içinde setTimeout fonksiyonu kullanarak, promise’imizin içine ekleyelim. 👇

Not: Gerçek hayatta zaman faktöründen de kaçınabilirsiniz. Bu tamamen işinizin doğasına bağlıdır.

let order = (time, work) => {
return new Promise((resolve, reject) => {
if (is_shop_open) {
setTimeout(() => {
// iş burada 👇 yapılıyor
resolve(work())

// 👇 Burada iş 1 için zaman ayarı
}, time)
} else {
reject(console.log("Our shop is closed"))
}
})
}

Şimdi, dondurma üretimine başlamak için yeni oluşturduğumuz fonksiyonu kullanacağız.

// Zamanı 👇 burada ayarlayın
order(2000, () => console.log(`${stocks.Fruits[0]} was selected`))
// Çalışmaya ☝️ başlamak için buraya bir fonksiyon iletin

2 saniye sonra sonuç şöyle görünür:

Promise Chaining

Bu metotta, .then işleyicisini kullanarak ilk görev tamamlandığında ne yapmamız gerektiğini tanımlıyoruz.

.then işleyicisi, orjinal promise’imiz çözüldüğünde (resolve olduğunda) bir promise return eder.

İşte bir örnek:

Daha basit hale getireyim: birine talimat vermeye benzer. Birini “Önce şunu yap, sonra bunu yap, daha sonra diğer bir şeyi yap, sonra…, sonra…, sonra…” ve bu şekilde devam etmesini söylersiniz.

  • İlk görev, orjinal promise’imizdir.
  • Görevlerin geri kalanı, küçük bir iş parçası tamamlandığında promise’imizi return eder.

Bunu projemizde uygulayalım. Kodunuzun en altında aşağıdaki satırları yazın. 👇

Not: .then işleyicinizin içine return kelimesini yazmayı unutmayın. Aksi takdirde, düzgün çalışmayacaktır. Merak ediyorsanız, adımları tamamladıktan sonra return’u kaldırmayı deneyin:

order(2000, () => console.log(`${stocks.Fruits[0]} was selected`)).then(() => {
return order(0000, () => console.log("production has started"))
})

Ve işte sonuç: 👇

// strawberry was selected
// production has started

Aynı sistemi kullanarak projemizi bitirelim:👇

// step 1
order(2000, () => console.log(`${stocks.Fruits[0]} was selected`))
// step 2
.then(() => {
return order(0000, () => console.log("production has started"))
})

// step 3
.then(() => {
return order(2000, () => console.log("Fruit has been chopped"))
})

// step 4
.then(() => {
return order(1000, () =>
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`)
)
})

// step 5
.then(() => {
return order(1000, () => console.log("start the machine"))
})

// step 6
.then(() => {
return order(2000, () => console.log(`ice cream placed on ${stocks.holder[1]}`))
})

// step 7
.then(() => {
return order(3000, () => console.log(`${stocks.toppings[0]} as toppings`))
})

// Step 8
.then(() => {
return order(2000, () => console.log("Serve Ice Cream"))
})

İşte sonuç: 👇

// strawberry was selected
// production has started
// Fruit has been chopped
// water and ice added
// start the machine
// ice cream placed on cup
// chocolate as toppings
// Serve Ice Cream

Error handling

Bir şeyler ters gittiğinde hataları halletmenin bir yoluna ihtiyacımız var. Ama önce, promise döngüsünü anlamamız gerekiyor.

Hatalarımızı yakalamak için değişkenimizi false olarak değiştirelim.

let is_shop_open = false

Bu da dükkanımızın kapalı olduğu manasına geliyor. Artık müşterilerimize dondurma satmıyoruz.

Bunu halletmek için .catch işleyicisini kullanıyoruz. Tıpkı .then gibi, sadece orjinal promise’imiz reddedildiğinde (reject olduğunda) bir promise return eder.

Burada küçük bir hatırlatma:

  • .then, bir promise çözüldüğünde resolved çalışır.
  • .catch, bir promise reddedildiğinde rejected çalışır.

En alta inin ve aşağıdaki kodu yazın:👇

// step 1
order(2000, () => console.log(`${stocks.Fruits[0]} was selected`))
// step 2
.then(() => {
return order(0000, () => console.log("production has started"))
})

// step 3
.then(() => {
return order(2000, () => console.log("Fruit has been chopped"))
})

// step 4
.then(() => {
return order(1000, () =>
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`)
)
})

// step 5
.then(() => {
return order(1000, () => console.log("start the machine"))
})

// step 6
.then(() => {
return order(2000, () => console.log(`ice cream placed on ${stocks.holder[1]}`))
})

// step 7
.then(() => {
return order(3000, () => console.log(`${stocks.toppings[0]} as toppings`))
})

// Step 8
.then(() => {
return order(2000, () => console.log("Serve Ice Cream"))
})

.catch(() => {
console.log("Customer left")
})

Önceki .then işleyiciniz ile .catch işleyiciniz arasında hiçbir şey olmaması gerektiğini unutmayın.

İşte cevap:👇

// Our shop is closed  <== reject
// Customer left <== catch

Bu kod hakkında dikkat edilmesi gereken birkaç nokta:

  • Birinci mesaj promise’imizin reject() kısmından geliyor.
  • İkinci mesaj .catch işleyicisinden geliyor.

.finally() handler

Promise’imizin resolve veya reject olup olmadığına bakılmaksızın çalışan .finally işleyicisi denen bir mekanizma var.

Örneğin: Müşterilere hizmet versekte vermesekte gün sonunda dükkanımız kapanacaktır.

Hadi bunu test edelim: 👇

// step 1
order(2000, () => console.log(`${stocks.Fruits[0]} was selected`))
// step 2
.then(() => {
return order(0000, () => console.log("production has started"))
})

// step 3
.then(() => {
return order(2000, () => console.log("Fruit has been chopped"))
})

// step 4
.then(() => {
return order(1000, () =>
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`)
)
})

// step 5
.then(() => {
return order(1000, () => console.log("start the machine"))
})

// step 6
.then(() => {
return order(2000, () => console.log(`ice cream placed on ${stocks.holder[1]}`))
})

// step 7
.then(() => {
return order(3000, () => console.log(`${stocks.toppings[0]} as toppings`))
})

// Step 8
.then(() => {
return order(2000, () => console.log("Serve Ice Cream"))
})

.catch(() => {
console.log("Customer left")
})

.finally(() => {
console.log("end of day")
})

Sonuç:👇

// Our shop is closed  <== reject
// Customer left <== catch
// end of day <== finally

Async/Await JavaScript’te Nasıl Çalışır?

Promise’leri yazmanın daha iyi bir yolunu sunuyor ve kodumuzu basit ve temiz tutmamıza yardımcı oluyor.

Tek yapmanız gereken herhangi bir fonksiyondan önce async kelimesini yazmak ve böylece bir promise haline geliyor.

Promises vs Async/Await

async/await’ten önce, bir promise yapmak için bunu yazdık:

function order() {
return new Promise((resolve, reject) => {})
}

Şimdi async/await kullanarak yazalım:

async function order() {
// Kodlar buraya yazılacak
}

Daha öncesinde anlamalısın ->

  • try ve catch anahtar kelimeleri nasıl kullanılır?
  • await anahtar kelimesi nasıl kullanılır?

try ve catch Anahtar Kelimeleri Nasıl Kullanılır?

Hatalarımızı yakalamak için catch kullanırken, kodumuzu çalıştırmak için try anahtar kelimesini kullanırız. Promise’lere baktığımızda gördüğümüz kavramın aynısı.

Bir karşılaştırma yapalım. Formatın küçük bir demosunu göreceğiz, ardından kodlamaya başlayacağız.

Promise

function kitchen() {
return new Promise((resolve, reject) => {
if (true) {
resolve("promise is fulfilled")
} else {
reject("error caught here")
}
})
}

kitchen() // run the code
.then() // next step
.then() // next step
.catch() // error caught here
.finally() // end of the promise [optional]

Async/Await

//👇 Sihirli Anahtar Kelime
async function kitchen() {
try {
// Sahte bir problem oluşturalım
await abc
} catch (error) {
console.log("abc does not exist", error)
} finally {
console.log("Runs code anyways")
}
}

kitchen()

Panik yapmayın, şimdi await anahtar kelimesini ele alacağız.

JavaScript’in Await Anahtar Kelimesi Nasıl Kullanılır?

await anahtar kelimesi JavaScript’in bir promise gerçekleşene ve sonucunu return edene kadar beklemesini sağlar.

Dondurma dükkanımıza geri dönelim. Bir müşterinin çikolata mı yoksa fıstık mı tercih edeceğini bilmiyoruz. Bu yüzden makinemizi durdumamız ve müşterimize dondurmasının üzerine ne istediğini sormamız gerekiyor.

  • bulaşıkları yıkamak
  • masaları temizlemek
  • siparişleri almak

Hangi sosun kullanılacağını sormak için küçük bir promise oluşturalım. İşlem üç saniye sürer.

function toppings_choice() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log("which topping would you love?"))
}, 3000)
})
}

Şimdi async anahtar kelimesi ile kitchen() fonksiyonumuzu oluşturalım.

async function kitchen() {
console.log("A")
console.log("B")
console.log("C")

await toppings_choice()

console.log("D")
console.log("E")
}

// Trigger the function
kitchen()

kitchen() çağrısı altına başka görevler ekleyelim.

function toppings_choice() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log("which topping would you love?"))
}, 3000)
})
}

async function kitchen() {
console.log("A")
console.log("B")
console.log("C")

await toppings_choice()

console.log("D")
console.log("E")
}

kitchen()

// Bunları ekliyoruz
console.log("doing the dishes")
console.log("cleaning the tables")
console.log("taking orders")

İşte sonuç:

// A
// B
// C
// doing the dishes
// cleaning the tables
// taking orders
// which topping would you love?
// D
// E

Müşterimize “Sos seçiminiz nedir?” diye sormak için kelimenin tam anlamıyla mutfağımızın dışına çıkıyoruz. Bu arada başka işler de yapılıyor.

Bir kere, sos seçimini alıyoruz, mutfağa giriyoruz ve işi bitiriyoruz.

Küçük not

Async/Await kullanırken, promise’lerin temel bir parçası olan .then, .catch ve .finally işleyicilerini de kullanabilirsiniz.

Dondurma dükkanımızı tekrar açalım

İki fonksiyon oluşturacağız ->

  • kitchen: dondurma yapmak için
  • time: her küçük görevin alacağı süreyi atamak için

Başlayalım! İlk olarak, time fonksiyonunu oluşturalım:

let is_shop_open = true

function time(ms) {
return new Promise((resolve, reject) => {
if (is_shop_open) {
setTimeout(resolve, ms)
} else {
reject(console.log("Shop is closed"))
}
})
}

Şimdi kitchen fonksiyonumuzu oluşturalım:

async function kitchen() {
try {
// talimatlar burada
} catch (error) {
// hata yönetimi burada
}
}

kitchen()

Küçük talimatlar verelim ve kitchen fonksiyonumuzun çalışıp çalışmadığını test edelim:

async function kitchen() {
try {
// bu görev 1 için gereken süre
await time(2000)
console.log(`${stocks.Fruits[0]} was selected`)
} catch (error) {
console.log("Customer left", error)
} finally {
console.log("Day ended, shop closed")
}
}

Dükkan açıkken sonuç böyle: 👇

// strawberry was selected
// Day ended, shop closed

Dükkan kapandiğında ise sonuç: 👇

// Shop is closed <== reject
// Customer left undefined <== catch
// Day ended, shop closed <== finally

Projemizi tamamlayalım.

İlk olarak dükkanımızı açalım.

let is_shop_open = true

Şimdi kitchen() fonksiyonumuz içindeki adımları yazalım: 👇

async function kitchen() {
try {
await time(2000)
console.log(`${stocks.Fruits[0]} was selected`)

await time(0000)
console.log("production has started")

await time(2000)
console.log("fruit has been chopped")

await time(1000)
console.log(`${stocks.liquid[0]} and ${stocks.liquid[1]} added`)

await time(1000)
console.log("start the machine")

await time(2000)
console.log(`ice cream placed on ${stocks.holder[1]}`)

await time(3000)
console.log(`${stocks.toppings[0]} as toppings`)

await time(2000)
console.log("Serve Ice Cream")
} catch (error) {
console.log("customer left")
}
}

kitchen()

Sonuç: 👇

// strawberry was selected
// production has started
// fruit has been chopped
// water and ice added
// start the machine
// ice cream placed on cup
// chocolate as toppings
// Serve Ice Cream

Sonuç

Sonuna kadar okuduğunuz için tebrikler! Bu makalede öğrendikleriniz:

  • Senkron ve asenkron sistemler arasındaki fark
  • Asenkron JavaScript mekanizmasını kullanan 3 teknik (callback, promise ve async/await)

Bu makale size yardımcı olduysa, lütfen bana desteğinizi göstermek için abone olun ve aşağıdaki alkış 👏 düğmesine birkaç kez tıklayın. 👇

Want to Connect?

TwitterGitHub

--

--

Teo
FullStack Programming

💻 Freelance Developer 🙌 • 💯 Web Üzerine Türkçe İçerikler⚡