Rumah >hujung hadapan web >tutorial js >Storan Tempatan Async Sedia untuk Membantu Anda

Storan Tempatan Async Sedia untuk Membantu Anda

Mary-Kate Olsen
Mary-Kate Olsenasal
2024-12-22 22:22:14700semak imbas

Apabila anda mendengar frasa "Storan Tempatan Async", apakah yang terlintas di fikiran? Anda mungkin pada mulanya menganggap ia merujuk kepada beberapa pelaksanaan ajaib storan tempatan berasaskan pelayar. Namun, andaian ini tidak betul. Storan Tempatan Async tidak berkaitan dengan penyemak imbas mahupun mekanisme storan biasa. Mungkin satu atau dua perpustakaan yang telah anda gunakan menggunakannya di bawah hud. Dalam kebanyakan kes, ciri ini boleh menyelamatkan anda daripada berurusan dengan kod yang tidak kemas.

Apakah Storan Tempatan Async?

Storan Tempatan Async ialah ciri yang diperkenalkan dalam Node.js, pada mulanya ditambah dalam versi v13.10.0 dan v12.17.0, dan kemudiannya distabilkan dalam v16.4.0. Ia adalah sebahagian daripada modul async_hooks, yang menyediakan cara untuk menjejak sumber tak segerak dalam aplikasi Node.js. Ciri ini membolehkan penciptaan konteks kongsi yang boleh diakses oleh pelbagai fungsi tak segerak tanpa melepaskannya secara eksplisit. Konteks tersedia dalam setiap (dan sahaja) operasi yang dilaksanakan dalam panggilan balik yang dihantar kepada kaedah run() bagi contoh AsyncLocalStorage.

Corak untuk menggunakan AsyncLocalStorage

Sebelum menyelami contoh, mari jelaskan corak yang akan kami gunakan.

Permulaan

import { AsyncLocalStorage } from "async_hooks";
import { Context } from "./types";

export const asyncLocalStorage = new AsyncLocalStorage<Context>();

// export const authAsyncLocalStorage = new AuthAsyncLocalStorage<AuthContext>()

Dalam modul di atas, kami memulakan tika AsyncLocalStorage dan mengeksportnya sebagai pembolehubah.

Penggunaan

asyncLocalStorage.run({ userId }, async () => {
  const usersData: UserData = await collectUsersData();
  console.log("usersData", usersData);
});

// (method) AsyncLocalStorage<unknown>.run<Promise<void>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload)

Kaedah run() mengambil dua argumen: storan, yang mengandungi data yang ingin kami kongsikan dan panggil balik, di mana kami meletakkan logik kami. Akibatnya, storan boleh diakses dalam setiap panggilan fungsi dalam panggilan balik, membolehkan perkongsian data yang lancar merentas operasi tak segerak.

async function collectUsersData() {
  const context = asyncLocalStorage.getStore();
}

Untuk mengakses konteks, kami mengimport tika kami dan memanggil kaedah asyncLocalStorage.getStore(). Perkara yang menarik ialah storan yang diambil daripada getStore() ditaip kerana kami menghantar jenis Konteks kepada AsyncLocalStorage semasa pemula: new AsyncLocalStorage().

Storan Tempatan Async sebagai konteks pengesahan

Tiada aplikasi web tanpa sistem pengesahan. Kami mesti mengesahkan token pengesahan dan mengekstrak maklumat pengguna. Sebaik sahaja kami memperoleh identiti pengguna, kami ingin menyediakannya dalam pengendali laluan dan mengelakkan kod pendua dalam setiap satu. Mari lihat cara kami boleh menggunakan AsyncLocalStorage untuk melaksanakan konteks pengesahan sambil memastikan kod kami bersih.

Saya memilih fastify untuk contoh ini.

Menurut dokumentasi fastify ialah:

Rangka kerja web overhed yang pantas dan rendah, untuk Node.js

Ok, mari mulakan:

  1. Pasang fastify:
import { AsyncLocalStorage } from "async_hooks";
import { Context } from "./types";

export const asyncLocalStorage = new AsyncLocalStorage<Context>();

// export const authAsyncLocalStorage = new AuthAsyncLocalStorage<AuthContext>()
  1. Tentukan jenis untuk konteks pengesahan kami:
asyncLocalStorage.run({ userId }, async () => {
  const usersData: UserData = await collectUsersData();
  console.log("usersData", usersData);
});

// (method) AsyncLocalStorage<unknown>.run<Promise<void>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload)
  1. Mulakan tika AsyncLocalStorage, tetapkan ia kepada pembolehubah dan eksport pembolehubah. Ingat untuk lulus jenis yang berkaitan: new AsyncLocalStorage().
async function collectUsersData() {
  const context = asyncLocalStorage.getStore();
}
  1. Mulakan contoh Fastify dan tambahkan utiliti untuk pengendalian ralat:
npm install fastify

Kini tiba bahagian yang sangat penting. Kami akan menambah cangkuk onRequest untuk membalut pengendali dengan kaedah authAsyncLocalStorage.run().

type Context = Map<"userId", string>;

Selepas pengesahan berjaya, kami memanggil kaedah run() daripada authAsyncLocalStorage kami. Sebagai hujah storan, kami lulus konteks auth dengan userId yang diambil daripada token. Dalam panggilan balik, kami memanggil fungsi selesai untuk meneruskan kitaran hayat Fastify.

Jika kami mempunyai semakan pengesahan yang memerlukan operasi tak segerak, kami harus menambahkannya pada panggilan balik. Ini kerana, menurut dokumentasi:

panggilan balik yang dilakukan tidak tersedia apabila menggunakan async/menunggu atau mengembalikan Janji. Jika anda melakukan panggilan balik yang telah selesai dalam situasi ini, tingkah laku yang tidak dijangka mungkin berlaku, mis. seruan pendua pengendali

Berikut ialah contoh bagaimana ia mungkin kelihatan:

import { AsyncLocalStorage } from "async_hooks";
import { Context } from "./types";

export const authAsyncLocalStorage = new AsyncLocalStorage<Context>();

Contoh kami hanya mempunyai satu laluan yang dilindungi. Dalam senario yang lebih kompleks, anda mungkin perlu membungkus hanya laluan tertentu dengan konteks pengesahan. Dalam kes sedemikian, anda boleh sama ada:

  1. Balut cangkuk onRequest dalam pemalam tersuai yang digunakan hanya pada laluan tertentu.
  2. Tambah logik perbezaan laluan dalam cangkuk onRequest itu sendiri.

Baiklah, konteks kami ditetapkan dan kami kini boleh menentukan laluan yang dilindungi:

import Fastify from "fastify";

/* other code... */

const app = Fastify();

function sendUnauthorized(reply: FastifyReply, message: string) {
  reply.code(401).send({ error: `Unauthorized: ${message}` });
}

/* other code... */

Kodnya agak mudah. Kami mengimport authAsyncLocalStorage, mendapatkan semula userId, memulakan UserRepository dan mengambil data. Pendekatan ini memastikan pengendali laluan bersih dan fokus.

Meneroka Cara Next.js menggunakan Storan Tempatan Async

Dalam contoh ini, kami akan melaksanakan semula pembantu kuki daripada Next.js. Tetapi tunggu—ini adalah siaran tentang AsyncLocalStorage, bukan? Jadi mengapa kita bercakap tentang kuki? Jawapannya mudah: Next.js menggunakan AsyncLocalStorage untuk mengurus kuki pada pelayan. Itulah sebabnya membaca kuki dalam komponen pelayan adalah semudah:

import Fastify from "fastify";
import { authAsyncLocalStorage } from "./context";
import { getUserIdFromToken, validateToken } from "./utils";

/* other code... */

app.addHook(
  "onRequest",
  (request: FastifyRequest, reply: FastifyReply, done: () => void) => {
    const accessToken = request.headers.authorization?.split(" ")[1];
    const isTokenValid = validateToken(accessToken);
    if (!isTokenValid) {
      sendUnauthorized(reply, "Access token is invalid");
    }
    const userId = accessToken ? getUserIdFromToken(accessToken) : null;

    if (!userId) {
      sendUnauthorized(reply, "Invalid or expired token");
    }
    authAsyncLocalStorage.run(new Map([["userId", userId]]), async () => {
      await new Promise((resolve) => setTimeout(resolve, 2000));
      sendUnauthorized(reply, "Invalid or expired token");
      done();
    });
  },
);

/* other code... */

Kami menggunakan fungsi kuki yang dieksport dari sebelah/pengepala, yang menyediakan beberapa kaedah untuk mengurus kuki. Tetapi bagaimana ini boleh dilakukan secara teknikal?

Kini tiba masanya untuk memulakan pelaksanaan semula kami"

Pertama, saya ingin menyatakan bahawa contoh ini adalah berdasarkan pengetahuan yang saya peroleh daripada video hebat, oleh Lee Robinson dan menyelam dalam repositori Next.js.

Dalam contoh ini, kami akan menggunakan Hono sebagai rangka kerja pelayan kami. Saya memilihnya atas dua sebab:

  1. Saya baru sahaja mahu mencubanya.
  2. Ia menawarkan sokongan padu untuk JSX.

Pasang pertama Hono:

import { AsyncLocalStorage } from "async_hooks";
import { Context } from "./types";

export const asyncLocalStorage = new AsyncLocalStorage<Context>();

// export const authAsyncLocalStorage = new AuthAsyncLocalStorage<AuthContext>()

Sekarang, mulakan Hono dan tambah perisian tengah:

asyncLocalStorage.run({ userId }, async () => {
  const usersData: UserData = await collectUsersData();
  console.log("usersData", usersData);
});

// (method) AsyncLocalStorage<unknown>.run<Promise<void>>(store: unknown, callback: () => Promise<void>): Promise<void> (+1 overload)

Kod itu menyerupai perisian tengah daripada contoh Fastify, bukan? Untuk menetapkan konteks, kami menggunakan setCookieContext, yang diimport daripada modul kuki — pelaksanaan mudah tersuai kami bagi fungsi kuki. Mari ikuti fungsi setCookieContext dan navigasi ke modul dari mana ia diimport:

async function collectUsersData() {
  const context = asyncLocalStorage.getStore();
}

Fungsi setCookieContext (yang nilai pulangannya kami hantar ke cookieAsyncLocalStorage.run() dalam middleware Hono) mengekstrak kuki daripada parameter c, yang mewakili konteks hono dan menggabungkannya dengan penutupan yang menyediakan fungsi utiliti untuk mengurus kuki.

Fungsi kuki kami mereplikasi kefungsian kuki dari sebelah/pengepala. Ia menggunakan kaedah cookieAsyncLocalStorage.getStore() untuk mengakses konteks yang sama yang dihantar kepada cookieAsyncLocalStorage.run() apabila ia dipanggil.

Kami membungkus pemulangan fungsi kuki kami dalam janji untuk meniru gelagat pelaksanaan Next.js. Sebelum versi 15, fungsi ini adalah segerak. Sekarang, dalam kod Next.js semasa, kaedah yang dikembalikan oleh kuki dilampirkan pada objek janji, seperti yang ditunjukkan dalam contoh mudah berikut:

npm install fastify

Perkara lain yang patut dinyatakan ialah dalam kes kami, menggunakan cookies.setCookie dan cookies.deleteCookie sentiasa menimbulkan ralat, serupa dengan tingkah laku yang diperhatikan dalam Next.js apabila menetapkan kuki dalam komponen pelayan. Kami mengekod logik ini kerana, dalam pelaksanaan asal, sama ada kami boleh menggunakan setCookie atau deleteCookie bergantung pada sifat fasa(WorkUnitPhase) yang disimpan dalam storan yang dipanggil RequestStore(ini ialah pelaksanaan AsyncLocalStorage dan juga menyimpan kuki). Walau bagaimanapun, topik itu lebih sesuai untuk siaran lain. Untuk memastikan contoh ini mudah, mari tinggalkan simulasi WorkUnitPhase.

Sekarang kami perlu menambah kod React kami.

  1. Tambah komponen Apl:
type Context = Map<"userId", string>;
  1. Tambah komponen untuk menguruskan kuki:
import { AsyncLocalStorage } from "async_hooks";
import { Context } from "./types";

export const authAsyncLocalStorage = new AsyncLocalStorage<Context>();

Penggunaan kuki adalah serupa dengan cara ia digunakan dalam komponen pelayan Next.js React.

  1. Tambah pengendali laluan untuk memaparkan templat:
import Fastify from "fastify";

/* other code... */

const app = Fastify();

function sendUnauthorized(reply: FastifyReply, message: string) {
  reply.code(401).send({ error: `Unauthorized: ${message}` });
}

/* other code... */

Templat kami diberikan oleh kaedah html daripada konteks hono. Perkara utama di sini ialah pengendali laluan berjalan dalam kaedah asyncLocalStorage.run(), yang mengambil cookieContext. Akibatnya, kami boleh mengakses konteks ini dalam komponen DisplayCookies melalui fungsi kuki.

Tidak mungkin untuk menetapkan kuki dalam komponen pelayan React, jadi kami perlu melakukannya secara manual:

Async Local Storage is Here to Help You

Jom muat semula halaman:

Async Local Storage is Here to Help You

Dan inilah kami, kuki kami berjaya diambil dan dipaparkan.

Kesimpulan

Terdapat banyak lagi kes penggunaan untuk asyncLocalStorage. Ciri ini membolehkan anda membina konteks tersuai dalam hampir mana-mana rangka kerja pelayan. Konteks asyncLocalStorage dirangkumkan dalam pelaksanaan kaedah run(), menjadikannya mudah untuk diurus. Ia sesuai untuk mengendalikan senario berasaskan permintaan. API adalah ringkas dan fleksibel, mendayakan kebolehskalaan dengan mencipta kejadian untuk setiap keadaan. Anda boleh mengekalkan konteks berasingan dengan lancar untuk perkara seperti pengesahan, pengelogan dan bendera ciri.

Walaupun manfaatnya, terdapat beberapa pertimbangan yang perlu diingat. Saya pernah mendengar pendapat bahawa asyncLocalStorage memperkenalkan terlalu banyak 'ajaib' ke dalam kod. Saya akan mengakui bahawa apabila saya mula-mula menggunakan ciri ini, saya mengambil sedikit masa untuk memahami sepenuhnya konsep itu. Perkara lain yang perlu dipertimbangkan ialah mengimport konteks ke dalam modul mewujudkan kebergantungan baharu yang perlu anda uruskan. Walau bagaimanapun, pada akhirnya, menghantar nilai melalui panggilan fungsi bersarang dalam adalah lebih teruk.

Terima kasih kerana membaca, dan jumpa lagi dalam siaran seterusnya!?

PS: Anda boleh dapatkan contoh (tambah satu bonus) di sini

Sumber Bog Post: https://www.aboutjs.dev/en/async-local-storage-is-here-to-help-you

Atas ialah kandungan terperinci Storan Tempatan Async Sedia untuk Membantu Anda. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn