Jadual Kandungan
Pengenalan kepada Suntikan Ketergantungan
循环依赖问题
总结
附录
Rumah alat pembangunan VSCode Analisis terperinci suntikan pergantungan dalam VSCode

Analisis terperinci suntikan pergantungan dalam VSCode

Nov 24, 2022 pm 09:25 PM
vscode typescript visual studio code

Analisis terperinci suntikan pergantungan dalam VSCode

Dalam proses membaca kod VSCode, kita akan mendapati terdapat sejumlah besar penghias yang digunakan dalam setiap modul untuk menghiasi modul dan modul-modulnya. bergantung kepada. Apakah tujuan melakukan ini? Dalam artikel ini kami akan menganalisisnya secara terperinci. [Pembelajaran yang disyorkan: Tutorial vscode, Video pengaturcaraan]

Pengenalan kepada Suntikan Ketergantungan

Jika terdapat modul A sedemikian, pelaksanaannya bergantung pada satu lagi Modul B mempunyai keupayaan, jadi bagaimana ia harus direka bentuk? Secara ringkasnya, kita boleh membuat instantiate modul B dalam pembina modul A, supaya kita boleh menggunakan keupayaan modul B di dalam modul A.

class A {
  constructor() {
    this.b = new B();
  }
}

class B {}

const a = new A();
Salin selepas log masuk

Tetapi terdapat dua masalah dengan ini Pertama, semasa proses instantiasi modul A, modul B perlu dibuat secara manual, dan jika kebergantungan modul B berubah, modul A juga perlu. diubah suai, yang membawa kepada gandingan kod.

Kedua, dalam projek yang kompleks, apabila kita membuat instantiat modul A, adalah sukar untuk menentukan sama ada modul B bergantung pada modul lain dan telah digunakan, jadi modul B boleh digunakan beberapa kali. Jika modul B lebih berat atau perlu direka bentuk sebagai singleton, ini akan menyebabkan masalah prestasi.

Oleh itu, cara yang lebih baik ialah menyerahkan instantiasi semua modul kepada rangka kerja luar, dan biarkan rangka kerja menguruskan proses instantiasi modul secara seragam, supaya kedua-dua masalah di atas dapat diselesaikan.

class A {
  constructor(private b: B) {
    this.b = b;
  }
}

class B {}

class C {
  constructor(private a: A, private b: B) {
    this.b = b;
  }
}

const b = new B();
const a = new A(b);
const c = new C(a, b);
Salin selepas log masuk

Kaedah menyuntik objek bergantung dari luar untuk mengelakkan kebergantungan instantiate di dalam modul dipanggil Dependencies Inject (DI). Ini ialah corak reka bentuk biasa dalam kejuruteraan perisian Kita boleh melihat aplikasi corak reka bentuk ini dalam rangka kerja seperti Java's Spring, JS's Angular, dan Node's NestJS.

Sudah tentu, dalam aplikasi sebenar, disebabkan bilangan modul yang banyak dan kebergantungan yang kompleks, sukar bagi kami untuk merancang pemasaan instantiasi setiap modul dan menulis jujukan instantiasi modul seperti contoh di atas. Selain itu, banyak modul mungkin tidak perlu dibuat pada kali pertama dan perlu dibuat instantiat atas permintaan Oleh itu, instantiasi bersatu kasar tidak digalakkan.

Jadi kami memerlukan rangka kerja bersatu untuk menganalisis dan mengurus proses instantiasi semua modul Ini adalah peranan rangka kerja suntikan pergantungan.

Dengan bantuan keupayaan penghias TypeScript, VSCode melaksanakan rangka kerja suntikan pergantungan yang sangat ringan. Mula-mula kita boleh melaksanakannya secara ringkas untuk merungkai misteri reka bentuk yang bijak ini.

Reka bentuk rangka kerja suntikan pergantungan yang paling mudah

Ia hanya mengambil dua langkah untuk melaksanakan rangka kerja suntikan pergantungan Satu ialah mengisytiharkan dan mendaftarkan modul ke dalam rangka kerja untuk pengurusan, dan satu lagi adalah dalam pembina modul Istiharkan modul yang anda perlukan untuk bergantung.

Mari kita lihat dahulu proses pendaftaran modul, yang memerlukan keupayaan penghias kelas TypeScript. Apabila menyuntik, kita hanya perlu menentukan sama ada modul telah didaftarkan. Jika tidak, memasukkan id modul (di sini dipermudahkan kepada nama Kelas modul) dan jenis boleh melengkapkan pendaftaran modul tunggal.

export function Injectable(): ClassDecorator {
  return (Target: Class): any => {
    if (!collection.providers.has(Target.name)) {
      collection.providers.set(Target.name, target);
    }
    return target;
  };
}
Salin selepas log masuk
Seterusnya, mari kita lihat cara modul mengisytiharkan kebergantungan, yang memerlukan keupayaan penghias harta TypeScript. Apabila menyuntik, kami mula-mula menentukan sama ada modul bergantung telah dijadikan instantiated Jika tidak, modul bergantung akan instantiated dan disimpan dalam rangka kerja untuk pengurusan. Akhirnya mengembalikan contoh modul yang telah digunakan.

export function Inject(): PropertyDecorator {
  return (target: Property, propertyKey: string) => {

    const instance = collection.dependencies.get(propertyKey);
    if (!instance) {
      const DependencyProvider: Class = collection.providers.get(propertyKey);
      collection.dependencies.set(propertyKey, new DependencyProvider());
    }

    target[propertyKey] = collection.dependencies.get(propertyKey);
  };
}
Salin selepas log masuk
Akhir sekali, anda hanya perlu memastikan rangka kerja itu sendiri dibuat seketika sebelum projek dijalankan. (Diwakili sebagai penyuntik dalam contoh)

export class ServiceCollection {
  readonly providers = new Map<string, any>();
  readonly dependencies = new Map<string, any>();
}

const collection = new ServiceCollection();
export default collection;
Salin selepas log masuk
Dengan cara ini, rangka kerja suntikan kebergantungan yang paling mudah dilengkapkan. Memandangkan jenis modul dan kejadian disimpan, ia membolehkan instantiasi atas permintaan modul tanpa perlu memulakan semua modul apabila projek dimulakan.

Kita boleh cuba memanggilnya, mengambil contoh yang diberikan di atas:

@injectable()
class A {
  constructor(@inject() private b: B) {
    this.b = b;
  }
}

@injectable()
class B {}

class C {
  constructor(@inject() private a: A, @inject() private b: B) {
    this.b = b;
  }
}

const c = new C();
Salin selepas log masuk
Tidak perlu mengetahui pemasaan instantiasi modul A dan B, hanya mulakan mana-mana modul secara langsung, dan rangka kerja secara automatik akan Membantu anda mencari dan membuat instantiate semua modul bergantung.

Pelaksanaan pengumpulan kebergantungan VSCode

Di atas memperkenalkan pelaksanaan paling mudah bagi rangka kerja suntikan kebergantungan. Tetapi apabila kami benar-benar membaca kod sumber VSCode, kami mendapati bahawa rangka kerja suntikan pergantungan dalam VSCode nampaknya tidak digunakan dengan cara ini.

Sebagai contoh, dalam perkhidmatan pengesahan di bawah, kami mendapati bahawa kelas tidak mempunyai

sebagai koleksi kebergantungan kelas dan perkhidmatan bergantung juga secara langsung menggunakan nama kelasnya sebagai penghias dan bukannya @injectable(). @inject()

// src\vs\workbench\services\authentication\browser\authenticationService.ts
export class AuthenticationService extends Disposable implements IAuthenticationService {
  constructor(
    @IActivityService private readonly activityService: IActivityService,
    @IExtensionService private readonly extensionService: IExtensionService,
    @IStorageService private readonly storageService: IStorageService,
    @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
    @IDialogService private readonly dialogService: IDialogService,
    @IQuickInputService private readonly quickInputService: IQuickInputService
  ) {}
}
Salin selepas log masuk
Malah, pengubah suai di sini sebenarnya tidak menunjuk kepada nama kelas, tetapi id deskriptor sumber dengan nama yang sama (dipanggil

dalam VSCode), yang biasanya dikenal pasti melalui rentetan atau Simbol. ServiceIdentifier

Gunakan

sebagai id dan bukannya hanya mendaftarkan Perkhidmatan melalui nama kelas sebagai id, yang berguna untuk menangani masalah bahawa antara muka dalam projek mungkin mempunyai pelaksanaan polimorfik dan memerlukan berbilang kejadian kelas dengan nama yang sama pada masa yang sama. ServiceIdentifier

此外,在构造 ServiceIdentifier 时,我们便可以将该类声明注入框架,而无需@injectable()显示调用了。

那么,这样一个 ServiceIdentifier 该如何构造呢?

// src\vs\platform\instantiation\common\instantiation.ts
/**
 * The *only* valid way to create a {{ServiceIdentifier}}.
 */
export function createDecorator<T>(serviceId: string): ServiceIdentifier<T> {

  if (_util.serviceIds.has(serviceId)) {
    return _util.serviceIds.get(serviceId)!;
  }

  const id = <any>function (target: Function, key: string, index: number): any {
    if (arguments.length !== 3) {
      throw new Error(&#39;@IServiceName-decorator can only be used to decorate a parameter&#39;);
    }
    storeServiceDependency(id, target, index);
  };

  id.toString = () => serviceId;

  _util.serviceIds.set(serviceId, id);
  return id;
}

// 被 ServiceIdentifier 装饰的类在运行时,将收集该类的依赖,注入到框架中。
function storeServiceDependency(id: Function, target: Function, index: number): void {
  if ((target as any)[_util.DI_TARGET] === target) {
    (target as any)[_util.DI_DEPENDENCIES].push({ id, index });
  } else {
    (target as any)[_util.DI_DEPENDENCIES] = [{ id, index }];
    (target as any)[_util.DI_TARGET] = target;
  }
}
Salin selepas log masuk

我们仅需通过createDecorator方法为类创建一个唯一的ServiceIdentifier,并将其作为修饰符即可。

以上面的 AuthenticationService 为例,若所依赖的 ActivityService 需要变更多态实现,仅需修改 ServiceIdentifier 修饰符确定实现方式即可,无需更改业务的调用代码。

export const IActivityServicePlanA = createDecorator<IActivityService>("IActivityServicePlanA");
export const IActivityServicePlanB = createDecorator<IActivityService>("IActivityServicePlanB");
export interface IActivityService {...}

export class AuthenticationService {
  constructor(
    @IActivityServicePlanA private readonly activityService: IActivityService,
  ) {}
}
Salin selepas log masuk

循环依赖问题

模块之间的依赖关系是有可能存在循环依赖的,比如 A 依赖 B,B 依赖 A。这种情况下进行两个模块的实例化会造成死循环,因此我们需要在框架中加入循环依赖检测机制来进行规避。

本质上,一个健康的模块依赖关系就是一个有向无环图(DAG),我们之前介绍过有向无环图在 excel 表格函数中的应用,放在依赖注入框架的设计中也同样适用。

我们可以通过深度优先搜索(DFS)来检测模块之间的依赖关系,如果发现存在循环依赖,则抛出异常。

// src/vs/platform/instantiation/common/instantiationService.ts
while (true) {
  let roots = graph.roots();

  // if there is no more roots but still
  // nodes in the graph we have a cycle
  if (roots.length === 0) {
    if (graph.length !== 0) {
      throwCycleError();
    }
    break;
  }

  for (let root of roots) {
    // create instance and overwrite the service collections
    const instance = this._createInstance(root.data.desc, []);
    this._services.set(root.data.id, instance);
    graph.removeNode(root.data);
  }
}
Salin selepas log masuk

该方法通过获取图节点的出度,将该类的全部依赖提取出来作为roots,然后逐个实例化,并从途中剥离该依赖节点。由于依赖树的构建是逐层依赖的,因此按顺序实例化即可。当发现该类的所有依赖都被实例化后,图中仍存在节点,则认为存在循环依赖,抛出异常。

总结

本篇文章简要介绍并实现了一个依赖注入框架,并解析了VSCode在实际问题上做出的一些改进。

实际上 VSCode 的依赖注入能力还有很多细节需要处理。例如异步实例化能力支持,通过封装 Deferred 类取得Promise执行状态,等等,在此就不一一展开了。感兴趣的同学可以参考 VSCode 源码:src/vs/platform/instantiation/common/instantiationService.ts,做更进一步的学习。

附录

最简 DI 框架完整 demo:github.com/realDuang/d…

更多关于VSCode的相关知识,请访问:vscode基础教程

Atas ialah kandungan terperinci Analisis terperinci suntikan pergantungan dalam VSCode. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
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

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
2 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Repo: Cara menghidupkan semula rakan sepasukan
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Cara mendapatkan biji gergasi
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk melihat dokumen perkataan dalam vscode Bagaimana untuk melihat dokumen perkataan dalam vscode Bagaimana untuk melihat dokumen perkataan dalam vscode Bagaimana untuk melihat dokumen perkataan dalam vscode May 09, 2024 am 09:37 AM

Mula-mula, buka perisian vscode pada komputer, klik ikon [Sambungan] di sebelah kiri, seperti yang ditunjukkan dalam ① dalam rajah Kemudian, masukkan [pemeriksa pejabat] dalam kotak carian antara muka sambungan, seperti yang ditunjukkan dalam ② dalam rajah . Kemudian, daripada carian Pilih [officeviewer] untuk memasang dalam hasil, seperti yang ditunjukkan dalam ③ dalam rajah Akhir sekali, buka fail, seperti docx, pdf, dsb., seperti yang ditunjukkan di bawah

Cara melukis carta alir dengan vscode_Cara melukis carta alir dengan kod visual_studio Cara melukis carta alir dengan vscode_Cara melukis carta alir dengan kod visual_studio Apr 23, 2024 pm 02:13 PM

Mula-mula, buka kod studio visual pada komputer, klik empat butang segi empat sama di sebelah kiri, kemudian masukkan draw.io dalam kotak carian untuk menanya pemalam, klik Pasang Selepas pemasangan, buat fail test.drawio baharu, kemudian pilih fail test.drawio, masukkan mod penyuntingan di sebelah kiri Terdapat pelbagai grafik di sebelah Anda boleh melukis carta alir dengan memilih sesuka hati, klik Fail → Benamkan → svg dan kemudian pilih Salin svg kod. Tampal kod svg yang disalin ke dalam kod html Buka halaman web html dan anda boleh melihatnya. Klik pada gambar pada halaman web untuk melompat ke carta alir carta alir Di sini, kami memilih untuk mengklik pada corak pensel di sudut kanan bawah untuk melompat ke halaman web.

Bagaimana untuk menulis Maude dalam Vscode_Bagaimana untuk menulis Maude dalam Vscode Bagaimana untuk menulis Maude dalam Vscode_Bagaimana untuk menulis Maude dalam Vscode Apr 23, 2024 am 10:25 AM

Mula-mula, anda boleh mencari pemalam Maude dalam pengurus pemalam vscode. Kemudian, buat fail baharu dengan sambungan maude untuk menggunakan coretan kod maude dan penyerlahan sintaks. Terminal -> Terminal Baharu boleh membuka terminal terbina dalam vscode dalam folder semasa untuk menjalankan program maude atau full-maude. Dalam tutorial rasmi maude, terdapat juga contoh klien http, yang boleh dipanggil dan dijalankan seperti yang ditunjukkan dalam rajah. Jika anda ingin mengaitkan fail dengan sambungan fm, buka tetapan, cari perkaitan fail dalam tetapan pengguna dan buka settings.json. Cuma tambahkan entri pada perkaitan fail, iaitu entri daripada *.fm ke maude. Tetapi penuh

Caltech Cina menggunakan AI untuk menumbangkan bukti matematik! Mempercepatkan 5 kali terkejut Tao Zhexuan, 80% langkah matematik adalah automatik sepenuhnya Caltech Cina menggunakan AI untuk menumbangkan bukti matematik! Mempercepatkan 5 kali terkejut Tao Zhexuan, 80% langkah matematik adalah automatik sepenuhnya Apr 23, 2024 pm 03:01 PM

LeanCopilot, alat matematik formal yang telah dipuji oleh ramai ahli matematik seperti Terence Tao, telah berkembang semula? Sebentar tadi, profesor Caltech Anima Anandkumar mengumumkan bahawa pasukan itu mengeluarkan versi diperluaskan kertas LeanCopilot dan mengemas kini pangkalan kod. Alamat kertas imej: https://arxiv.org/pdf/2404.12534.pdf Percubaan terkini menunjukkan bahawa alat Copilot ini boleh mengautomasikan lebih daripada 80% langkah pembuktian matematik! Rekod ini adalah 2.3 kali lebih baik daripada aesop garis dasar sebelumnya. Dan, seperti sebelum ini, ia adalah sumber terbuka di bawah lesen MIT. Dalam gambar, dia ialah Song Peiyang, seorang budak Cina

Bagaimana untuk membolehkan kemas kini latar belakang dalam vscode Bagaimana untuk membolehkan kemas kini latar belakang dalam vscode Bagaimana untuk membolehkan kemas kini latar belakang dalam vscode Bagaimana untuk membolehkan kemas kini latar belakang dalam vscode May 09, 2024 am 09:52 AM

1. Pertama, selepas membuka antara muka, klik menu fail di sudut kiri atas 2. Kemudian, klik butang tetapan dalam lajur pilihan 3. Kemudian, dalam halaman tetapan yang melompat, cari bahagian kemas kini. Akhir sekali, klik tetikus untuk menyemak dan mendayakannya Muat turun dan pasang butang versi VSCode baharu di latar belakang pada Windows dan mulakan semula program.

Bagaimana untuk menambah fail ke vscode ruang kerja Bagaimana untuk menambah fail ke vscode ruang kerja Bagaimana untuk menambah fail ke vscode ruang kerja Bagaimana untuk menambah fail ke vscode ruang kerja May 09, 2024 am 09:43 AM

1. Mula-mula, buka perisian vscode, klik ikon explorer, dan cari tetingkap ruang kerja 2. Kemudian, klik menu fail di sudut kiri atas dan cari pilihan tambah folder ke ruang kerja 3. Akhir sekali, cari lokasi folder dalam cakera tempatan , klik butang tambah

Bagaimana untuk melumpuhkan fail konfigurasi wsl dalam vscode Bagaimana untuk melumpuhkan fail konfigurasi wsl dalam vscode Bagaimana untuk melumpuhkan fail konfigurasi wsl dalam vscode Bagaimana untuk melumpuhkan fail konfigurasi wsl dalam vscode May 09, 2024 am 10:30 AM

1. Mula-mula, buka pilihan tetapan dalam menu tetapan 2. Kemudian, cari lajur terminal dalam halaman yang biasa digunakan 3. Akhir sekali, nyahtanda butang usewslprofiles di sebelah kanan lajur.

Bagaimana untuk menetapkan sisipan lancar animasi dalam tutorial VScode VScode untuk menetapkan sisipan lancar animasi Bagaimana untuk menetapkan sisipan lancar animasi dalam tutorial VScode VScode untuk menetapkan sisipan lancar animasi May 09, 2024 am 09:49 AM

1. Mula-mula, selepas membuka antara muka, klik antara muka ruang kerja 2. Kemudian, dalam panel penyuntingan terbuka, klik menu Fail 3. Kemudian, klik butang Tetapan di bawah lajur Keutamaan 4. Akhir sekali, klik tetikus untuk menyemak CursorSmoothCaretAnimation butang dan simpan Hanya tetapkannya

See all articles