JavaScript’te vaatler – JSManifest

JavaScript'te vaatler – JSManifest

JavaScript’te yeniyseniz ve vaatlerin nasıl çalıştığını anlamakta zorlanıyorsanız, umarım bu makale onları daha net anlamanıza yardımcı olur.

Bununla birlikte, bu makale vaatlerin anlaşılmasında biraz emin olmayanlar için hazırlanmıştır.

Bu gönderi, aşağıdakileri kullanarak vaatleri yerine getirme üzerinden geçmeyecek zaman uyumsuz/bekleme işlevsellik açısından aynı şey olsalar da, yalnızca bu zaman uyumsuz/bekleme çoğu durumda daha sözdizimsel şekerdir.

Ne”

Sözler aslında bir süredir dışarıda önceki JavaScript’e özgüydüler. Örneğin, sözler yerel hale gelmeden önce bu kalıbı uygulayan iki kitaplık Q ve ne zaman.

Peki vaatler nelerdir? JavaScript nesnelerindeki vaatler asenkron bir işlemin nihai olarak tamamlanmasını veya başarısızlığını temsil eder. Geri arama yaklaşımını kullanarak veya vaatlerle zaman uyumsuz işlemler gerçekleştirerek sonuçlar elde edebilirsiniz. Fakat ikisi arasında bazı küçük farklılıklar vardır.

Geri aramalar ve vaatler arasındaki temel fark

İkisi arasındaki temel fark, geri arama yaklaşımını kullanırken normalde sadece bir geri arama iletmek bir fonksiyona bir şeyin sonucunu almak için tamamlandıktan sonra çağrılır, oysa sözlerde geri aramalar eklersiniz döndürülen söz nesnesinde.

Geri aramalar:

function getMoneyBack(money, callback) {
  if (typeof money !== 'number') {
    callback(null, new Error('money is not a number'))
  } else {
    callback(money)
  }
}

const money = getMoneyBack(1200)
console.log(money)

vaatler:

function getMoneyBack(money) {
  return new Promise((resolve, reject) => {
    if (typeof money !== 'number') {
      reject(new Error('money is not a number'))
    } else {
      resolve(money)
    }
  })
}

getMoneyBack(1200).then((money) => {
  console.log(money)
})

Söz Nesnesi

Az önce söz verdiğimiz iyi oldu nesnelerçünkü bunlar JavaScript’te vaatleri oluşturan çekirdektir.

Yani soru şu, Niye JavaScript’te sözlere ihtiyacımız var mı?

Bu soruyu daha iyi yanıtlamak için geri arama yaklaşımını kullanmanın neden böyle olmadığını sormamız gerekir. “yeterli” oradaki javascript geliştiricilerinin çoğu için.

geri arama cehennemi

Geri arama yaklaşımını kullanmanın yaygın bir sorunu, sonunda gerçekleştirmemiz gerekmesidir. çoklu asenkron işlemler olarak bilinen bir şeye kolayca ulaşabiliriz. geri arama cehennemiyönetilemez ve okunması zor kodlara yol açtığı için bir kabusa dönüşebilen , her geliştiricinin en kötü kâbus.

İşte buna bir örnek:

function getFrogsWithVitalSigns(params, callback) {
  let frogIds, frogsListWithVitalSignsData
  api.fetchFrogs(params, (frogs, error) => {
    if (error) {
      console.error(error)
      return
    } else {
      frogIds = frogs.map(({ id }) => id)
      
      api.fetchFrogsVitalSigns(
        frogIds,
        (frogsListWithEncryptedVitalSigns, err) => {
          if (err) {
            
          } else {
            
            api.decryptFrogsListVitalSigns(
              frogsListWithEncryptedVitalSigns,
              'pepsi',
              (data, errorr) => {
                if (errorrr) {
                  throw new Error('An error occurred in the final api call')
                } else {
                  if (Array.isArray(data)) {
                    frogsListWithVitalSignsData = data
                  } else {
                    frogsListWithVitalSignsData = data.map(
                      ({ vital_signs }) => vital_signs,
                    )
                    console.log(frogsListWithVitalSignsData)
                  }
                }
              },
            )
          }
        },
      )
    }
  })
}

const frogsWithVitalSigns = getFrogsWithVitalSigns({
  offset: 50,
})
  .then((result) => {
    console.log(result)
  })
  .catch((error) => {
    console.error(error)
  })

Kod pasajında ​​görsel olarak bazı garip şekiller oluştuğunu görebilirsiniz. Sadece 3 asenkron API çağrısından geri arama cehennemi, olağan yukarıdan aşağıya yönün tersine batmaya başlamıştı.

Sözleri zincirleyerek kodu ilk işleyicinin kökünde tutabildiğimiz için artık bir sorun olmaktan çıkıyor. .then yöntemler:

function getFrogsWithVitalSigns(params, callback) {
  let frogIds, frogsListWithVitalSignsData
  api
    .fetchFrogs(params)
    .then((frogs) => {
      frogIds = frogs.map(({ id }) => id)
      
      return api.fetchFrogsVitalSigns(frogIds)
    })
    .then((frogsListWithEncryptedVitalSigns) => {
      
      return api.decryptFrogsListVitalSigns(
        frogsListWithEncryptedVitalSigns,
        'pepsi',
      )
    })
    .then((data) => {
      if (Array.isArray(data)) {
        frogsListWithVitalSignsData = data
      } else {
        frogsListWithVitalSignsData = data.map(
          ({ vital_signs }) => vital_signs,
        )
        console.log(frogsListWithVitalSignsData)
      }
    })
    .catch((error) => {
      console.error(error)
    })
  })
}

const frogsWithVitalSigns = getFrogsWithVitalSigns({
  offset: 50,
})
  .then((result) => {
    console.log(result)
  })
  .catch((error) => {
    console.error(error)
  })

Geri arama kodu parçacığında, yalnızca birkaç düzey daha derine yerleştirilseydik, işler çirkinleşmeye ve yönetilmesi zorlaşmaya başlar.

Geri Arama Cehenneminden Oluşan Sorunlar

Sadece bu “geri arama cehennemini” temsil eden önceki kod parçacığımıza bakarak, vaatlerin dile iyi bir katkı olduğunu söylemek için yeterli kanıt olarak hizmet eden, bundan ortaya çıkan tehlikeli sorunların bir listesini bulabiliriz:

  1. Okumak gittikçe zorlaşıyordu
    1. Kod iki yönde hareket etmeye başlıyordu (yukarıdan aşağıya, sonra soldan sağa)
  2. Yönetmek gittikçe zorlaşıyordu
    1. Kod daha derine yerleştirildiğinden ne olduğu belli değildi.
    2. yapardık Her zaman Dış kapsamlarda önceden bildirilmiş olan aynı adlara sahip değişkenleri yanlışlıkla bildirmediğimizden emin olmalıyız (buna gölgeleme)
    3. hesabını vermek zorunda kaldık üç üç farklı yerde farklı hatalar.
      1. hatta zorunda kaldık Adını değiştirmek yapmadığımızdan emin olmak için her hata gölge üstündeki hata. Bu işlem dizisinde ek isteklerde bulunursak, yukarıdaki kapsamlardaki hatalarla çakışmayan ek değişken adları bulmamız gerekir.

Örneklere yakından bakarsak, bu sorunların çoğunun vaatleri zincirleme yaparak çözüldüğünü fark edeceğiz. .thenbundan sonra bahsedeceğiz.

Söz Zincirleme

Bir eşzamansız görev zinciri yürütmemiz gerektiğinde, söz zinciri oluşturma kesinlikle yararlı hale gelir. Zincirlenen her görev, yalnızca bir önceki görev tamamlanır tamamlanmaz başlayabilir. .thenzincirin s.

Şunlar .then bloklar dahili olarak ayarlanır, böylece geri arama işlevlerinin daha sonra her birine uygulanan bir söz vermesine izin verirler. .then zincirde.

Geri döndüğün herhangi bir şey .then çözülür biter söz vermekreddedilenlere ek olarak söz vermek gelen .catch bloklar.

İşte bunun kısa ve hızlı bir örneği:

const add = (num1, num2) => new Promise((resolve) => resolve(num1 + num2))

add(2, 4)
  .then((result) => {
    console.log(result) 
    return result + 10
  })
  .then((result) => {
    console.log(result) 
    return result
  })
  .then((result) => {
    console.log(result) 
  })

Söz Yöntemleri

JavaScript’teki Promise yapıcısı, vaatlerden bir veya daha fazla sonucu almak için kullanılabilecek birkaç statik yöntem tanımlar:

söz.hepsi

Bir grup eşzamansız işlem biriktirmek ve sonunda değerlerinin her birini bir dizi olarak almak istediğinizde, bir Bu amacı karşılayan söz verme yöntemlerinden Promise.all.

Promise.all olduğunda işlemlerin sonucunu toplar. tüm operasyonlar başarıyla sonuçlandı. Bu şuna benzer Promise.allSettledsadece burada söz en azından bir hatayla reddeder bir bu operasyonların sonu başarısız–Hangi sonunda içinde biter .catch söz zincirinin bloğu.

Söz verme reddi şu durumlarda meydana gelebilir: hiç çalışmasının başlangıcından bittiği zamana kadar olan noktadır. Reddedilme meydana gelirse önceki tüm sonuçlar tamamlandıktan sonra olan şey şu ki, bitiremeyenler iptal edilecek ve sona erecek asla Bitiricilik. Başka bir deyişle, onlardan biri “tüm” ya da hiçbir şey anlaşma.

İşte basit bir kod örneği Promise.all yöntem tüketir getFrogs ve getLizards hangi vaatler ve sonuçları içinde bir dizi olarak alır .then işleyici bunları yerel depoya kaydetmeden önce:

const getFrogs = new Promise((resolve) => {
  resolve([
    { id: 'mlo29naz', name: 'larry', born: '2016-02-22' },
    { id: 'lp2qmsmw', name: 'sally', born: '2018-09-13' },
  ])
})

const getLizards = new Promise((resolve) => {
  resolve([
    { id: 'aom39d', name: 'john', born: '2017-08-11' },
    { id: '20fja93', name: 'chris', born: '2017-01-30' },
  ])
})

function addToStorage(item) {
  if (item) {
    let prevItems = localStorage.getItem('items')
    if (typeof prevItems === 'string') {
      prevItems = JSON.parse(prevItems)
    } else {
      prevItems = []
    }
    const newItems = [...prevItems, item]
    localStorage.setItem('items', JSON.stringify(newItems))
  }
}

let allItems = []

Promise.all([getFrogs, getLizards])
  .then(([frogs, lizards]) => {
    localStorage.clear()

    frogs.forEach((frog) => {
      allItems.push(frog)
    })
    lizards.forEach((lizard) => {
      allItems.push(lizard)
    })
    allItems.forEach((item) => {
      addToStorage(item)
    })
  })
  .catch((error) => {
    console.error(error)
  })

console.log(localStorage.getItem('items'))

söz.yarış

Bu yöntem, yinelenebilir bir durumdaki sözlerden biri, söz konusu sözün değeri veya nedeni ile çözüldüğünde veya reddettiğinde, ya yerine getiren ya da reddeden bir söz verir.

İşte arasında basit bir örnek promise1 ve promise2 ve Promise.race yürürlükteki yöntem:

const promise1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve('some result')
  }, 200)
})

const promise2 = new Promise((resolve, reject) => {
  reject(new Error('some promise2 error'))
})

Promise.race([promise1, promise2])
  .then((result) => {
    console.log(result)
  })
  .catch((error) => {
    console.error(error)
  })

Bu sonucu verecek olan:

Döndürülen değer, diğer söz 200 milisaniye geciktiği için sözün reddi oldu.

Promise.allYerleşik

bu Promise.allSettled yöntem sonuçta biraz benziyor Promise.all bunun dışında benzer bir hedefi paylaşırken hemen bir hatayı reddetmek yerine vaatlerden biri başarısız olduğunda, Promise.allSettled sonunda bir söz verecek her zaman çözer verilen vaatlerin tümü çözümlendikten veya reddedildikten sonra, sonuçları her bir öğenin söz verme işleminin sonucunu temsil ettiği bir dizide toplayarak. Bunun anlamı, yapacaksın Her zaman bir dizi veri türü ile biter.

İşte eylemde bunun bir örneği:

const add = (num1, num2) => new Promise((resolve) => resolve(num1 + num2))
const multiply = (num1, num2) => new Promise((resolve) => resolve(num1 * num2))
const fail = (num1) =>
  new Promise((resolve, reject) =>
    setTimeout(() => reject(new Error('You, my friend, were too late')), 200),
  )
const fail2 = (num1) =>
  new Promise((resolve, reject) =>
    setTimeout(
      () => reject(new Error('Being late is never a good habit')),
      100,
    ),
  )
const promises = [add(2, 4), multiply(5, 5), fail('hi'), fail2('hello')]

Promise.allSettled(promises)
  .then((result) => {
    console.log(result)
  })
  .catch((error) => {
    console.error(error)
  })

söz. yerleşik

söz. herhangi

Promise.any bir teklif üzerine ekleyerek Promise şu anda açık olan yapıcı TC39 sürecinin 3. aşaması.

Ne Promise.any yapılması önerilen bir yinelenebilir verilen sözlerin ve yerine getirilen bir sözün yerine getirilmesine yönelik girişimlerin ilk yerine getirilen veya reddedilen verilen söz AggregateError reddetme nedenlerini elinde tutuyorsa tüm verilen sözlerin reddedildiği kaynak.

Bunun anlamı, 15 vaat ve 14’ü tüketen bir operasyon olsaydı arızalı biri çözülürken, sonucu Promise.any çözülen sözün değeri olur:

const multiply = (num1, num2) => new Promise((resolve) => resolve(num1 * num2))
const fail = (num1) =>
  new Promise((resolve, reject) =>
    setTimeout(() => reject(new Error('You, my friend, were too late')), 200),
  )

const promises = [
  fail(2),
  fail(),
  fail(),
  multiply(2, 2),
  fail(2),
  fail(2),
  fail(2, 2),
  fail(29892),
  fail(2),
  fail(2, 2),
  fail('hello'),
  fail(2),
  fail(2),
  fail(1),
  fail(),
]

Promise.any(promises)
  .then((result) => {
    console.log(result) 
  })
  .catch((error) => {
    console.error(error)
  })

Bu konuda daha fazlasını okuyun burada.

Başarı/Hata İşlemi Gotcha

Başarılı veya başarısız taahhüt işlemlerinin şu varyasyonlar kullanılarak yapılabileceğini bilmekte fayda var:

Varyasyon 1:

add(5, 5).then(
  function success(result) {
    return result
  },
  function error(error) {
    console.error(error)
  },
)

Varyasyon 2:

add(5, 5)
  .then(function success(result) {
    return result
  })
  .catch(function(error) {
    console.error(error)
  })

Ancak bu iki örnek tam olarak aynı değil. Varyasyon 2’de, hata atmak çözümleme işleyicisinde, o zaman içinde yakalanan hatayı alabiliriz .tutmak engellemek:

add(5, 5)
  .then(function success(result) {
    throw new Error("You aren't getting passed me")
  })
  .catch(function(error) {
    
  })

Ancak 1. varyasyonda, çözümleme işleyicisinin içine bir hata atmaya çalışırsak, olumsuzluk hatayı yakalayabilmek:

add(5, 5).then(
  function success(result) {
    throw new Error("You aren't getting passed me")
  },
  function error(error) {
    
  },
)

Çözüm

Ve bu yazının sonu burada bitiyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!

Bir cevap yazın

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