Penggunaan praktis currying di js menggunakan contoh modul permintaan http

Halo semuanya! Bukan rahasia bagi siapa pun bahwa di dunia pemrograman ada banyak teknik, praktik, dan pola pemrograman (desain), tetapi seringkali, mempelajari sesuatu yang baru, sama sekali tidak jelas di mana dan bagaimana menerapkan ini baru.


Hari ini, menggunakan contoh membuat modul pembungkus kecil untuk bekerja dengan permintaan http, kami akan menganalisis manfaat nyata dari kari - penerimaan pemrograman fungsional.


Untuk semua pendatang baru dan mereka yang tertarik menggunakan pemrograman fungsional dalam praktiknya - selamat datang, mereka yang benar-benar mengerti apa itu currying - Saya menantikan komentar Anda tentang kode tersebut, karena seperti kata mereka - tidak ada batasan untuk kesempurnaan.


Jadi mari kita mulai


Tapi bukan dari konsep currying, tapi dari pernyataan masalah, di mana kita bisa menerapkannya.


Kami memiliki API blog tertentu yang bekerja sesuai dengan prinsip berikut (semua kecocokan dengan API nyata adalah kecelakaan):


  • permintaan ke /api/v1/index/ akan mengembalikan data untuk halaman utama
  • permintaan ke /api/v1/news/ akan mengembalikan data untuk halaman berita
  • permintaan ke /api/v1/articles/ akan mengembalikan data untuk daftar artikel
  • permintaan ke /api/v1/article/222/ akan mengembalikan halaman artikel dengan id 222
  • permintaan ke /api/v1/article/edit/222/ akan mengembalikan formulir pengeditan artikel dengan id 222
    ... dan seterusnya, lebih jauh, lebih jauh

Seperti yang Anda lihat, untuk mengakses API kita perlu beralih ke api versi tertentu v1 (seberapa sedikit itu akan tumbuh dan versi baru akan dirilis) dan kemudian merancang permintaan data lebih lanjut.


Oleh karena itu, dalam kode js, untuk mendapatkan data, misalnya, satu artikel dengan id 222, kita harus menulis (untuk menyederhanakan contoh sebanyak mungkin, kami menggunakan metode js fetch asli):


 fetch('/api/v1/article/222/') .then(/* success */) .catch(/* error */) 

Untuk mengedit artikel yang sama, kami akan meminta ini:


 fetch('/api/v1/article/edit/222/') .then(/* success */) .catch(/* error */) 

Tentunya Anda telah memperhatikan bahwa dalam permintaan kami ada banyak jalur duplikat. Misalnya, jalur dan versi ke API /api/v1/ , dan bekerja dengan satu artikel /api/v1/article/ dan /api/v1/article/edit/ .


Mengikuti aturan KERING favorit kami (Jangan Ulangi Sendiri), bagaimana cara mengoptimalkan kode permintaan API?


Kami dapat menambahkan bagian permintaan ke konstanta, misalnya:


 const API = '/api' const VERSION = '/v1' const ARTICLE = `${API}${VERSION}/article` 

Dan sekarang kita dapat menulis ulang contoh di atas dengan cara ini:


Permintaan Artikel


 fetch(`${ARTICLE}/222/`) 

Permintaan Editing Artikel


 fetch(`${ARTICLE}/edit/222/`) 

Kode tampaknya kurang, ada konstanta yang terkait dengan API, tetapi Anda dan saya tahu apa yang bisa dilakukan dengan lebih mudah.


Saya percaya bahwa masih ada opsi untuk memecahkan masalah, tetapi tugas kami adalah mempertimbangkan solusi menggunakan currying.


Prinsip membangun permintaan berdasarkan layanan http


Strateginya adalah membuat fungsi tertentu, dengan memanggil yang akan kami buat permintaan API.


Bagaimana cara kerjanya


Kami membuat permintaan dengan memanggil fungsi wrapper di atas pengambilan asli (sebut saja http. Di bawah ini adalah kode lengkap untuk fungsi ini), dalam argumen yang kami berikan parameter permintaan:


 cosnt httpToArticleId222 = http({ url: '/api/v1/article/222/', method: 'POST' }) 

Harap perhatikan bahwa hasil dari fungsi http ini adalah fungsi yang berisi url dan pengaturan permintaan metode.


Sekarang, dengan memanggil httpToArticleId222() kami benar-benar mengirim permintaan ke API.


Anda dapat melakukan pertanyaan desain yang lebih rumit dan bertahap. Dengan demikian, kita dapat membuat satu set fungsi yang sudah jadi dengan jalur API berkabel. Kami akan memanggil mereka layanan http.


Jadi, pertama, kami membangun layanan panggilan API (secara bersamaan menambahkan parameter permintaan yang tidak berubah untuk semua permintaan berikutnya, misalnya, metode)


 const httpAPI = http({ url: '/api', method: 'POST' }) 

Sekarang kami membuat layanan mengakses API dari versi pertama. Di masa mendatang, kami akan dapat membuat cabang permintaan terpisah dari layanan httpAPI ke versi API yang berbeda.


 const httpAPIv1 = httpAPI({ url: '/v1' }) 

Layanan untuk mengakses API versi pertama sudah siap. Sekarang kami akan membuat layanan untuk sisa data darinya (ingat daftar improvisasi di awal artikel)


Data Beranda


 const httpAPIv1Main = httpAPIv1({ url: '/index' }) 

Data Halaman Berita


 const httpAPIv1News = httpAPIv1({ url: '/news' }) 

Data Daftar Artikel


 const httpAPIv1Articles = httpAPIv1({ url: '/articles' }) 

Akhirnya kami sampai pada contoh utama kami, data untuk materi


 const httpAPIv1Article = httpAPIv1({ url: '/article' }) 

Bagaimana cara mendapatkan jalur untuk mengedit artikel? Tentu saja, Anda dapat menebaknya, kami memuat data dari fungsi httpAPIv1Article yang dibuat sebelumnya


 const httpAPIv1ArticleEdit = httpAPIv1({ url: '/edit' }) 

Hasil logis kecil


Jadi, kami memiliki daftar layanan yang indah, misalnya, dalam file terpisah, yang tidak mengganggu kami sama sekali. Jika ada sesuatu yang perlu diubah dalam permintaan, saya tahu persis di mana untuk mengedit.


 export { httpAPIv1Main, httpAPIv1News, httpAPIv1Articles, httpAPIv1Article, httpAPIv1ArticleEdit } 

Saya mengimpor layanan dengan fungsi tertentu


 import { httpAPIv1Article } from 'services' 

Dan saya mengeksekusi permintaan, pertama merekonstruksi dengan menambahkan id materi, dan kemudian saya memanggil fungsi untuk mengirim permintaan (seperti yang mereka katakan: "mudah")


 httpAPIv1Article({ url: ArticleID // id  -   })() .then(/* success */) .catch(/* error */) 

Bersih, cantik, mudah dimengerti (bukan iklan)


Bagaimana cara kerjanya


Kita dapat "memuat" suatu fungsi dengan data tepat karena currying.


Sedikit teori.
Currying adalah cara membangun fungsi dengan kemampuan untuk secara bertahap menerapkan argumennya. Ini dicapai dengan mengembalikan fungsi setelah dipanggil.


Contoh klasik adalah penambahan.
Kami memiliki fungsi penjumlahan, pertama kali kami menelepon, kami melewati angka pertama untuk pelipatan berikutnya. Setelah memanggilnya, kami mendapatkan fungsi baru yang mengharapkan nomor kedua untuk menghitung jumlahnya. Ini dia kode (sintaksis ES6)


 const sum = a => b => a + b 

Kami menyebutnya pertama kali (aplikasi parsial) dan menyimpan hasilnya dalam variabel, misalnya, sum13


 const sum13 = sum(13) 

Sekarang jumlah 13 kita juga dapat memanggil dengan nomor yang hilang, dalam argumen, yang hasilnya 13 + argumen kedua


 sum13(7) // =>  20 

Nah, bagaimana cara menerapkan ini pada tugas kita?


Kami membuat fungsi http , yang akan menjadi pembungkus pengambilan


 function http (paramUser) {} 

di mana paramUser adalah parameter permintaan yang diteruskan pada saat pemanggilan fungsi


Mari kita mulai menambahkan logika ke fungsi kita.


Tambahkan parameter permintaan yang ditetapkan secara default.


 function http (paramUser) { /** *  -,    * @type {string} */ let param = { method: 'GET', credentials: 'same-origin' } } 

Dan kemudian fungsi paramGen , yang menghasilkan parameter permintaan dari yang ditetapkan secara default dan ditentukan oleh pengguna (pada kenyataannya, hanya penggabungan dua objek)


 function http (paramUser) { /** *  -,    * @type {string} */ let param = { method: 'GET', credentials: 'same-origin' } /** *   , *  url  ,          * * @param {object} param   * @param {object} paramUser ,    * * @return {object}     */ function paramGen (param, paramUser) { let url = param.url || '' let newParam = Object.assign({}, param, paramUser) url += paramUser.url || '' newParam.url = url return newParam } } 

Kami melewati ke yang paling penting, kami menggambarkan kari


Fungsi yang dipanggil, misalnya, fabric dan dikembalikan oleh fungsi http akan membantu kita dalam hal ini.


 function http (paramUser) { /** *  -,    * @type {string} */ let param = { method: 'GET', credentials: 'same-origin' } /** *   , *  url  ,          * * @param {object} param   * @param {object} paramUser ,    * * @return {object}     */ function paramGen (param, paramUser) { let url = param.url || '' url += paramUser.url || '' let newParam = Object.assign({}, param, paramUser); newParam.url = url return newParam } /** *  ,     *  ,      * *  : * * -    ,        ,     * -   ,           * -   ,      * * @param {object} param ,       * @param {object} paramUser ,   * * @return {function || promise}   ,    (fetch),     */ function fabric (param, paramUser) { if (paramUser) { if (typeof paramUser === 'string') { return fabric.bind(null, paramGen(param, { url: paramUser })) } return fabric.bind(null, paramGen(param, paramUser)) } else { //  ,   ,   param    url, //       :) return fetch(param.url, param) } } return fabric.bind(null, paramGen(param, paramUser)) } 

Panggilan pertama ke fungsi http mengembalikan fungsi fabric , dengan parameter param diteruskan ke sana (dan dikonfigurasi oleh fungsi paramGen ), yang akan menunggu untuk itu. jam telepon nanti.


Misalnya, konfigurasikan permintaan


 let httpGift = http({ url: '//omozon.ru/givemegift/' }) 

Dan dengan memanggil httpgift , parameter yang dikirimkan diterapkan, sebagai hasilnya, kami kembali mengambil , jika kami ingin mengkonfigurasi ulang permintaan, kami hanya meneruskan parameter baru ke fungsi httpgift yang dihasilkan dan mengharapkannya dipanggil tanpa argumen


 httpGift() .then(/* success */) .catch(/* error */) 

Ringkasan


Berkat penggunaan currying dalam pengembangan berbagai modul, kami dapat mencapai fleksibilitas tinggi dalam penggunaan modul dan kemudahan pengujian. Seperti, misalnya, ketika mengatur arsitektur layanan untuk bekerja dengan API.


Seolah-olah kita membuat perpustakaan mini, menggunakan alat yang kita buat infrastruktur tunggal untuk aplikasi kita.


Saya harap informasi itu bermanfaat, jangan memukul keras, ini adalah artikel pertama saya dalam hidup saya :)


Semua kode yang dikompilasi, sampai jumpa lagi!

Source: https://habr.com/ru/post/id422661/


All Articles