Handlebars.js: saran fitur | Pembantu Sinkron/Asinkron

Dibuat pada 23 Jan 2014  ·  24Komentar  ·  Sumber: handlebars-lang/handlebars.js

Mendaftarkan pembantu sebagai Sync atau Async, Ini membantu untuk mendengarkan panggilan balik, dan mendapatkan data dari panggilan balik.

Komentar yang paling membantu

akan mencoba express-hbs - tapi saya pikir pada 2018 ini adalah hal yang aneh untuk tidak mendukung. Saya tahu bahwa ada pandangan murni bahwa hal-hal async tidak boleh dilakukan sebagai bagian dari tampilan tetapi sebaliknya dalam beberapa hal ajaib yang disebut pengontrol (seolah-olah MVC entah bagaimana "benar") - tetapi itu sedikit terlihat pendek untuk dua kunci alasan

a) perpustakaan eksternal - kebanyakan orang sekarang menulis sepenuhnya dengan async/menunggu - saya pikir dalam kode saya lebih dari 9 dari 10 fungsi async ... dalam beberapa kasus "berjaga-jaga". Tidak mendukung fungsi async berarti semua perpustakaan async tiba-tiba benar-benar tidak dapat diakses

b) fungsi pengontrol generik. Saya berpendapat bahwa sesuatu seperti ini:

    {{#query "select name, total from summary"}}
          <tr><td>{{this.name}}</td><td>{{this.total}}</td></tr>
    {{/query}}

lebih pendek, lebih bersih, lebih mudah dirawat, dan pada dasarnya lebih unggul dalam segala hal yang mungkin jika dibandingkan dengan memiliki fungsi pengontrol yang dipesan lebih dahulu yang memasukkan barang-barang itu ke dalam variabel dan meneruskannya ke templat, yang kemudian harus diketahui dan diakses oleh templat.

Semua 24 komentar

Ini telah muncul di masa lalu tetapi kami tidak menindaklanjutinya karena kasus penggunaannya tidak jelas. Karena setang masih harus menunggu hingga semua data tersedia untuk dirender, menyediakan evaluasi asinkron hanyalah sebuah kenyamanan untuk sesuatu yang dapat dilakukan oleh kode yang menghasilkan konteks dengan cara yang jauh lebih efisien.

Pada dasarnya menambahkan evaluasi async pada titik ini akan cukup mahal baik dalam hal kompatibilitas dan kinerja runtime yang saya tidak melihat kasus penggunaan untuk saat ini. Apakah Anda memiliki contoh nyata dari apa yang Anda coba lakukan?

Saya setuju dengan masalah kinerja, tetapi saya pikir, akan lebih baik, jika kita dapat membuatnya aysnc, misalnya, RegisterHelper & RegisterHelperAsync, atau semacamnya.

Sebenarnya, saya mulai berpikir tentang setang async ini, saat saya bekerja dengan node.js. Saya sedang mengerjakan beberapa aplikasi menggunakan express.js & mesin template yang saya gunakan adalah setang. Jadi, Jika saya perlu mendapatkan beberapa nilai dari panggilan basis data, saat mengkompilasi tampilan, itu tidak mungkin dengan kerja sinkron ini,

Sebagai contoh,

Handlebars.registerHelper('getDbValue', function(id) {
     var Model = require('./myModel.js');
     Model.getValue(id, function(data){
           return data;
     });
});

Contoh di atas tidak akan berfungsi, dan tidak mengembalikan apa pun. Berikut ini adalah konsep saya. Dan, saya tidak tahu, apakah itu sepenuhnya benar atau bisa diterapkan atau tidak. Hanya menggunakan fungsi panggilan balik alih-alih kembali, dalam hal metode async.

Handlebars.registerHelperAsync('getDbValue', function(id, callback) {
     var Model = require('./myModel.js');
     Model.getValue(id, function(data){
           callback(data);
           //or
           //callback(new Handlebars.SafeString(data)); //in case of safestring.
     });
});

Saya mengalami lebih banyak masalah seperti yang di atas, dan saya dapat menunjukkan lebih banyak contoh sesuai dengan skenario saya, jika ada yang tertarik dengan fitur ini.

Terima kasih

@robincsamuel , Saat memasukkan pencarian basis data dalam pembuatan tampilan, seluruh gagasan pemisahan MVC ada di jendela. Saya pikir Anda berargumen bahwa Anda mungkin tidak tahu bahwa Anda memerlukan data sampai tampilan dirender, tetapi bagi saya itu menyarankan fungsionalitas yang harus diimplementasikan pada tingkat pengontrol daripada saat membuat tampilan Anda. Dikombinasikan dengan pertimbangan kinerja yang disebutkan @kpdecker , pembantu async sepertinya salah. -- 2c saya

Saya hanya menggunakan contoh itu untuk menyampaikan masalah saya. Dan saya tidak mencoba untuk berdebat, tetapi, hanya membuat saran. Saya harap, ini akan membantu jika kita memanggil fungsi dengan panggilan balik dari pembantu. Bagaimanapun, terima kasih atas waktu Anda :) @kpdecker @jwilm

Pada titik ini pendirian proyek adalah bahwa resolusi data harus dilakukan sebelum memanggil template. Di luar logika bisnis di dalam atau di luar masalah template, resolusi async lebih merupakan perilaku utilitas yang perpustakaan lain seperti async jauh lebih cocok untuk ditangani.

Saya ingin mengomentari sesuatu. Meskipun akan membuang contoh DB ke luar jendela, ini bisa sangat membantu untuk templat mutasi. Misalnya, template dengan "subview" di dalamnya, dan Anda tidak ingin membaginya menjadi beberapa template lain. Saya hanya ingin memperbarui bagian dalam tampilan, dan memiliki logika sederhana untuk itu, alih-alih mengecat ulang seluruh tampilan saya (efek berkedip) atau meminta pengontrol saya untuk membangun semuanya untuk semua "tampilan mini" ini

Bagaimana menurut anda?

@tomasdev maksud saya :)

Fitur ini tersedia di node dengan express jika Anda menggunakan https://github.com/barc/express-hbs. Namun versi pembantu async tidak cocok dengan subekspresi dan beberapa kasus tepi lainnya.

Saya ingin melihat fitur ini dipertimbangkan kembali untuk dimasukkan dalam setang, atau setidaknya pertimbangkan bagaimana inti setang dapat mendukung ekstensi semacam ini dengan lebih baik.

Saya percaya Ghost menunjukkan usecase yang jelas dan valid (walaupun mungkin tidak umum) untuk pembantu async, karena lapisan tampilan kami dapat disesuaikan.

Di frontend, semua template Ghost disediakan oleh tema. Tema adalah lapisan setang, CSS, dan JS klien yang sangat tipis, satu-satunya data yang dapat diaksesnya adalah yang kami sediakan sebelumnya. Itu tidak memiliki akses ke pengontrol atau logika perubahan perilaku apa pun. Ini sangat disengaja.

Untuk memperluas API tema, kami ingin mulai menambahkan pembantu yang menentukan koleksi data tambahan yang ingin digunakan tema. Misalnya sesuatu seperti:

{{#fetch tags}}
.. do something with the list of tags..
{{else}}
No tags available
{{/fetch}}

Ghost memiliki JSON API yang tersedia baik secara internal maupun eksternal. Jadi kueri pengambilan ini akan dipetakan ke fungsi tag penelusuran kami. Itu tidak perlu menggunakan ajax/http ke semua titik akhir, sebagai gantinya, pembantu async dapat mengambil data ini dari API secara internal dan melanjutkan seperti biasa.

Saya tidak berpendapat bahwa ini adalah kasus penggunaan yang umum, dan saya menerimanya melanggar model MVC standar, tetapi saya yakin ini valid dan berguna.

@ErisDS Berita bagus! Dan saya juga tidak berpendapat bahwa ini adalah masalah umum, tetapi itu membantu.

Perlu dicatat dalam kasus ini, bahwa banyak dari operasi yang saat ini kami gunakan untuk pembantu async adalah sinkron di bawah tenda, tetapi mereka terstruktur sebagai janji.

Untuk memberikan contoh rinci...

Semua data di Ghost diakses melalui API internal. Ini termasuk info global seperti pengaturan. Permintaan ke API pengaturan mencapai cache dalam memori yang telah diisi sebelumnya sebelum mencapai database, jadi kami sebenarnya hanya mengembalikan variabel, tetapi dengan menyusun ini sebagai janji, mudah untuk pergi ke database jika kita perlu.

Ini juga memastikan semuanya konsisten - jika tidak, API pengaturan akan sinkron, dan semua permintaan data internal lainnya akan asinkron, yang tidak masuk akal.

Saya tahu bahwa menyusun segala sesuatu dengan janji bisa sangat membingungkan pada awalnya, tetapi itu adalah salah satu hal yang Anda tidak mengerti bagaimana Anda hidup tanpanya begitu Anda mendapatkannya. Dengan generator yang masuk ES6, dukungan untuk resolusi fungsi yang tidak sinkron akan dimasukkan langsung ke JavaScript - dan masalah serupa ini: https://github.com/wycats/handbars.js/issues/141 menyebutkan bahwa akan menyenangkan untuk membuat setang bekerja dengan hasil.

Saya tidak yakin bagaimana rilis HTMLbars yang akan datang mungkin berdampak pada ini, tetapi saya pikir itu setidaknya memerlukan diskusi lebih lanjut.

Mengalami kasus penggunaan lain saat mencoba membuat pembantu untuk resolusi acl. Ini akan cocok dengan template saya:

        {{#allowedTo 'edit' '/config'}}
            <li>
                <a href="/config">Config</a>
            </li>
        {{/allowedTo}}

Tetapi metode isAllowed yang sebenarnya dari node-acl tidak sinkron (memungkinkan backend database misalnya).

Solusinya adalah mengambil semua izin pengguna sebelumnya ( allowPermissions ), tapi itu agak gatal

@kpdecker Adakah pemikiran lebih lanjut tentang kasus penggunaan ini?

@ErisDS Saya mengerti keinginan di sini tetapi saya sangat ragu ini akan berhasil menjadi bahasa dalam bentuk panggilan balik atau janji. Ini adalah sesuatu yang sangat sulit untuk dilakukan secara bersih dari perspektif API dan secara efektif mengharuskan kami untuk menulis ulang sebagian besar mesin template untuk mendukungnya. Rekomendasi saya adalah semua ini ditangani sebelum siklus rendering dimasukkan oleh model/sumber data upstream.

Ide hasil adalah ide yang menarik tetapi jika seseorang ingin melihat apa yang diperlukan di sana, itu akan menjadi proyek penelitian yang luar biasa, tetapi dukungan browser untuk itu tampaknya sangat jauh bagi saya dan sejujurnya saya tidak main-main dengan salah satu fitur tersebut di salah satu proyek saya.

Hanya "dua" saya (baik, pasangan) sen yang mungkin ingin Anda pertimbangkan:

  • MVC tidak suci. Hal-hal tidak salah hanya karena tampaknya bertentangan dengan MVC. Kita harus mengevaluasi apakah alternatifnya tidak memberikan manfaat positif bersih daripada mengikuti MVC secara ketat.
  • Jika tampilan meminta pengontrol untuk data, bukan model secara langsung, itu bukan pelanggaran MVC, bukan?
  • Mungkin dapat dikatakan bahwa memiliki pengontrol yang mengetahui sebelumnya semua yang dibutuhkan tampilan adalah duplikasi informasi (yaitu informasi "X, Y, Z, W diperlukan" diduplikasi dalam tampilan dan pengontrol.) Dengan kata lain, kita saat ini praktek mungkin merupakan pelanggaran prinsip KERING, yang jauh lebih penting daripada MVC, imo.
  • Pukulan kinerja pembantu asinkron untuk tujuan memuat hanya model yang diperlukan untuk tampilan yang dirender dapat dengan mudah dikompensasikan dengan memuat lebih sedikit data dari database.

Saya mungkin dapat menawarkan contoh yang lebih baik di mana akan berguna untuk dimiliki.

Kami banyak bekerja dengan cordova untuk aplikasi seluler dan perlu melokalkan untuk banyak bahasa. Cordova menawarkan fungsi untuk membantu memformat tanggal, angka, mata uang, dan sebagainya.
Masalahnya adalah mereka semua memerlukan panggilan balik async.

Contoh:

Handlebars.registerHelper('stringToNumber', function(string, type)
{
    type = type || 'decimal';
    navigator.globalization.stringToNumber(string, function(number)
    {
        return number;
    }, function()
    {
        return NaN;
    }, {
        type: type
    });
});

Ini akan luar biasa untuk memiliki imo.

Saya telah menemukan paket setang-async di npm. Tapi ini sedikit lebih tua dan saya tidak tahu apakah itu berfungsi dengan versi Handlebars saat ini.

Saya juga baru saja menulis sesuatu yang serupa untuk janji. Paket stang yang dijanjikan memungkinkan Anda untuk mengembalikan janji dari dalam pembantu. Saya berencana untuk menggunakannya di salah satu proyek saya, tetapi sejauh ini belum digunakan di lingkungan produksi. Tetapi ada tes unit untuk beberapa kasus tepi (seperti memanggil async-helper dari dalam async block-helper) dan semuanya berwarna hijau...

@nknapp kedengarannya luar biasa! express-hbs memiliki dukungan async, dan async berfungsi untuk pembantu blok, tetapi pembantu async bersarang tidak berfungsi - jadi saya sangat tertarik untuk melihat ini berfungsi - berarti masih ada harapan untuk express-hbs :+1:

@ErisDS , apakah menurut Anda saya harus mempostingnya di sana. Saya tidak melakukannya sekarang karena express-hbs tidak dapat membuat sarang async helper. Fokus utama saya bukan express , tetapi generator README yang sedang saya kerjakan. Saya akan sangat menghargai orang lain untuk mencobanya ( janji-stang ) memberikan umpan balik.

Untuk menambah kasus penggunaan yang valid, bagaimana jika Anda perlu mengambil nilai dari DB terjemahan berdasarkan lokal saat ini?

<div class="howItWorks">
    {{{i18nFetch id=how-it-works locale=locale}}}
</div>

Selain itu, bagaimana dengan menambahkan blok CMS dari entri DB menggunakan id dinamis seperti:

<div class="searchCms">
    {{{cmsLoader 'search-{$term}' term=params.input defaultId='search-default'}}}
</div>

Ini sangat berguna untuk rendering sisi server (yaitu menggunakan express-handbars ).

Berikut ini kasus penggunaan lain: Saya sedang menulis generator dokumentasi untuk Swagger ( simple-swagger ), yang memungkinkan definisi skema eksternal. Saya ingin menulis helper Handlebars yang mengenali kapan skema didefinisikan secara eksternal, pergi ke URL yang disediakan di mana skema itu hidup, mengambilnya, dan menggunakan data itu untuk merender bagian template Handlebars itu. Jika saya harus mengambil data ini sebelum memanggil metode kompilasi Handlebars, saya harus mengulang secara rekursif melalui dokumen JSON yang strukturnya tidak saya ketahui sebelumnya, menemukan semua contoh skema eksternal, mengambilnya, dan memasukkannya ke dalam JSON.

Pada dasarnya, kapan pun template Handlebars digunakan untuk merender data skema JSON ( json-schema.org ), metode render asinkron akan berguna, karena skema JSON selalu mengizinkan subbagian skema untuk didefinisikan secara eksternal.

@dwhieb apakah Anda sudah melihat bootprint-swagger untuk generator dokumentasi? Hampir seperti yang Anda gambarkan (kecuali bahwa skema eksternal belum diterapkan, tetapi itu akan menjadi fitur yang hebat). Jika Anda memiliki umpan balik, silakan buka masalah di sana.

Dan, saya pikir stang yang dijanjikan bekerja cukup baik dengan pembantu async.

Saya memiliki kasus penggunaan di mana dapat menggunakan janji di pembantu akan berguna. Saya menggunakan setang untuk menghasilkan HTML untuk blog saya. Untuk membangun data terstruktur yang valid untuk setiap artikel, saya perlu mendapatkan dimensi yang saya gunakan untuk gambar artikel. Saat ini, saya sedang melakukannya seperti ini:

{{#imageSize post.frontMatter.previewImage}}
  <div itemprop="image" itemscope itemtype="https://schema.org/ImageObject">
    <meta itemprop="url" content="{{#staticResource ../post.frontMatter.previewImage}}{{/staticResource}}">
    <meta itemprop="width" content="{{width}}">
    <meta itemprop="height" content="{{height}}">
  </div>
{{/imageSize}}

Helper imageSize berfungsi karena ia membaca file secara sinkron, tetapi idealnya harus dapat melakukannya secara asinkron sehingga rendering halaman tidak diperlambat oleh I/O. Juga, melakukan ini untuk gambar di URL, bukan pada sistem file, tidak mungkin.

Saya akan melihat menggunakan stang yang dijanjikan dan hbs ekspres, tetapi saya pikir kemampuan untuk menggunakan janji dalam fungsi pembantu akan menjadi tambahan yang bagus untuk Stang!

FWIW, saya telah melakukan banyak rendering HTML asinkron menggunakan Hyperscript, hyperscript-helpers , ES7's async/await , dan ini benar-benar menyenangkan. Tapi tentu saja, solusi itu hanya berfungsi untuk HTML. Solusi asinkron dengan Handlebars akan memungkinkan kami menghasilkan jenis file lain secara asinkron... Namun untuk HTML, saya rasa saya tidak akan pernah melihat ke belakang!

akan mencoba express-hbs - tapi saya pikir pada 2018 ini adalah hal yang aneh untuk tidak mendukung. Saya tahu bahwa ada pandangan murni bahwa hal-hal async tidak boleh dilakukan sebagai bagian dari tampilan tetapi sebaliknya dalam beberapa hal ajaib yang disebut pengontrol (seolah-olah MVC entah bagaimana "benar") - tetapi itu sedikit terlihat pendek untuk dua kunci alasan

a) perpustakaan eksternal - kebanyakan orang sekarang menulis sepenuhnya dengan async/menunggu - saya pikir dalam kode saya lebih dari 9 dari 10 fungsi async ... dalam beberapa kasus "berjaga-jaga". Tidak mendukung fungsi async berarti semua perpustakaan async tiba-tiba benar-benar tidak dapat diakses

b) fungsi pengontrol generik. Saya berpendapat bahwa sesuatu seperti ini:

    {{#query "select name, total from summary"}}
          <tr><td>{{this.name}}</td><td>{{this.total}}</td></tr>
    {{/query}}

lebih pendek, lebih bersih, lebih mudah dirawat, dan pada dasarnya lebih unggul dalam segala hal yang mungkin jika dibandingkan dengan memiliki fungsi pengontrol yang dipesan lebih dahulu yang memasukkan barang-barang itu ke dalam variabel dan meneruskannya ke templat, yang kemudian harus diketahui dan diakses oleh templat.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

janus-reith picture janus-reith  ·  3Komentar

morgondag picture morgondag  ·  5Komentar

mattkime picture mattkime  ·  4Komentar

rizen picture rizen  ·  6Komentar

DylanPiercey picture DylanPiercey  ·  7Komentar