آقای Domenic Denicola در نسخههای بعدی، طرح پیشنهادی را مطرح کرده است که مربوط به بارگذاری داینامیک ماژولهای JS میباشد. البته کتابخانهها و روشهایی در حال حاضر برای این کار وجود دارند. با هم مثالهایی از این قابلیت را بررسی میکنیم.
یا یک مثال عملیاتی؛ فرض کنید با کلیک بر روی دکمهای میخواهیم یک Dialog را باز کنیم که منطق و قوائد مخصوص به خود را دارد و به صورت یک ماژول جداگانه نوشته شدهاست. کد زیر را مشاهده کنید:
این قابلیت هم وجود دارد که دو ماژول را که در یک فایل نوشته شدهاند نیز به صورت جداگانه استفاده کنید.
شما حتی میتوانید چند ماژول را باهم بارگذاری کنید و بعد از پایان بارگذاری همه ماژولها، یک عمل خاصی را انجام دهید. کد زیر را مشاهده کنید:
این موضوع را به کمک Promise با متد all انجام دادیم.
حتی شما میتوانید با قابلیت async و await نیز کدهای تمیزتر و با قابلیت خوانایی بالاتری را بنویسید. مثال زیر را مشاهده کنید:
در نسخه جدید Javascript قابلیتی برای import کردن ماژولها وجود دارد؛ ولی این قابلیت کاملا استاتیک میباشد. کد زیر را مشاهده کنید:
import someModule from './dir/someModule.js';
خوب سوالی که مطرح میشود این است که چه نیازی به بارگذاری داینامیک ماژولها داریم؟
جواب این سوال خیلی مشخص است. در import معمولی و استاتیک JS، ما تمام ماژولهای مورد نیاز در پروژه را فراخوانی میکنیم. اما شاید خیلی از این ماژولها در طول اجرای پروژه مورد نیاز نباشند و بر حسب رفتارهای کاربر نیاز به این ماژولها داشته باشیم. در این صورت هست که بارگذاری داینامیک ماژولها مطرح میشود. این قابلیت در جاوا اسکریپت به صورت built-in وجود ندارد. ولی با کتابخانههایی مانند RequireJS این قابلیت قابل استفاده هست. این Proposal توسط آقای Domenic Denicola مطرح شده است.
کد زیر مثال ساده از این قابلیت میباشد:
import('./dir/someModule.js') .then(someModule => someModule.foo());
یا یک مثال عملیاتی؛ فرض کنید با کلیک بر روی دکمهای میخواهیم یک Dialog را باز کنیم که منطق و قوائد مخصوص به خود را دارد و به صورت یک ماژول جداگانه نوشته شدهاست. کد زیر را مشاهده کنید:
button.addEventListener('click', event => { import('./dialogBox.js') .then(dialogBox => { dialogBox.open(); }) .catch(error => { /* Error handling */ }) });
این قابلیت هم وجود دارد که دو ماژول را که در یک فایل نوشته شدهاند نیز به صورت جداگانه استفاده کنید.
import('./myModule.js') .then(({export1, export2}) => { export1.run(); export2.fire(); });
شما حتی میتوانید چند ماژول را باهم بارگذاری کنید و بعد از پایان بارگذاری همه ماژولها، یک عمل خاصی را انجام دهید. کد زیر را مشاهده کنید:
Promise.all([ import('./module1.js'), import('./module2.js'), import('./module3.js'), ]) .then(([module1, module2, module3]) => { // code });
حتی شما میتوانید با قابلیت async و await نیز کدهای تمیزتر و با قابلیت خوانایی بالاتری را بنویسید. مثال زیر را مشاهده کنید:
async function main() { const myModule = await import('./myModule.js'); myModule.getInfo(); const {export1, export2} = await import('./myModule.js'); export1.run(); export2.fire() } main();
خوب خوشبختانه طرافداران NodeJS ماژول مربوط به این قابلیت را قبل از ارائه این قابلیت جدید در JS به صورت Packages در NPM فراهم کردهاند. لینک زیر را مشاهده کنید:
و Developerهای که از Webpack در پروژههای خود استفاده میکنند میتوانند از ماژول زیر استفاده کنند که توسط تیم Airbnb تهیه شده است:
و Developerهایی که از نسخه ۲ Webpack استفاده میکنند، میتوانند بحث Code Splitting را در راهنمای زیر مشاهده کنند:
البته آقای Jake Archibald کد جالبی را برای این قابلیت پیشنهاد دادهاست که ترکیبی از import استاتیک ES6 میباشد:
function importModule (url) { return new Promise((resolve, reject) => { const script = document.createElement("script"); const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2); script.type = "module"; script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`; script.onload = () => { resolve(window[tempGlobal]); delete window[tempGlobal]; script.remove(); }; script.onerror = () => { reject(new Error("Failed to load module script with URL " + url)); delete window[tempGlobal]; script.remove(); }; document.documentElement.appendChild(script); }); }