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();
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);
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 mudahIa 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; }; }
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); }; }
export class ServiceCollection { readonly providers = new Map<string, any>(); readonly dependencies = new Map<string, any>(); } const collection = new ServiceCollection(); export default collection;
@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();
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 ) {} }
dalam VSCode), yang biasanya dikenal pasti melalui rentetan atau Simbol. ServiceIdentifier
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('@IServiceName-decorator can only be used to decorate a parameter'); } 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; } }
我们仅需通过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, ) {} }
循环依赖问题
模块之间的依赖关系是有可能存在循环依赖的,比如 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); } }
该方法通过获取图节点的出度,将该类的全部依赖提取出来作为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!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

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

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.

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

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

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.

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

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.

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
