هیچ دوره ای در سبد خرید شما وجود ندارد
ابزارهایی برای برطرف کردن خطاهای سازندگان وب
سازندگان وب در TypeScript به شما پردازش همزمان را میدهند، اما آنها هم میتوانند آن را اشکالزدایی کنند. بااینحال، اگر کد سازنده وب خود را، بهعنوان یک تابع دیگر تنظیم کنید، میتوانید این اشکالزدایی را سادهتر کنید یا حتی سازنده وب خود را بهصورت پویا در زمان اجرا ایجاد کنید).
در ستون قبلی، من نشان دادم که چگونه یک سازنده وب را بهصورت دستی اجرا کنید و بهصورت همزمان در کد کلاینت آن را پردازش کنید. همانطور که گفتم، شروع کار یک سازنده وب بهطور مؤثر به شما یک موضوع برابر با آنچه با UI خود استفاده میکردید، میدهد – یک موضوعی که میتوانید آن را بهصورت آفلود پردازش کنید. شما میتوانید این پردازش را از طریق شیء postMessage و روش Worker انجام دهید.
بااینحال، اشکالزدایی یک سازنده وب را میتوان به چالش کشید. من یک استراتژی برای ساده کردن فرایند اشکالزدایی سراغ دارم اما قبل از اینکه بتوانم آن را توصیف کنم، باید با این موضوع با شما بحث کنم که چگونه میتوانید یک سازنده وب را بهصورت پویا در زمان اجرا بسازید یا فقط آن را در بقیه کد خود قرار دهید.
سازندگان وب بهصورت پویا
درحالیکه شما میتوانید کد سازنده وب خود را در یک فایل جداگانه از کدی که آن را مثلاً کد خود میدانید، قرار دهید، که این کار ضروری نیست. شما میتوانید سازنده را با عبور یک رشته از کد و از نوع “application / javascript” به سازنده یکشی بهصورت Blob ایجاد کنید. هنگامیکه شیء Blob ایجادشده است، شما میتوانید URL آن را از Blob استفادهشده از روش createObjectURL شیء URL، ایجاد کنید. این کار به شما اجازه میدهد تا یک سازنده وب را از یک رشته ایجاد کنید، همانطور که در این مثال گفتهشده است وقتی سازنده وب را ایجاد میکند، هر آنچه به آن ارسال میشود، بازمیگردد:
let b: Blob
b = new Blob([“onmessage = function(e) { postMessage(e.data); }”], { type: ‘application/javascript’ });
let url: string;
url = window.URL.createObjectURL(b);
w = new Worker(url);
انتقال یک رشته به یکشی Blob به شما اجازه میدهد تا بهطور پویا کد سازنده خود را در زمان اجرا اسمبل کنید. بااینحال، این کار بدون مشکل نیست. اولاً، البته کد در رشته شما بهجای TypeScript، باید در جاوا اسکریپت باشد، زیرا رشته به سازنده Blob در زمان اجرا منتقل نمیشود. در ثانی، اینکه شما زمان چک کردن کامپایلر را دریافت نمیکنید زیرا کد در یک رشته است. و درنهایت، این رشته برای رفع اشکالزدایی، آسانتر (و قابلتوجه شما که خواندن آن سختتر است) از کدی که در یک فایل جداگانه قرار دارد، نیست.
سازندگان وب بهصورت جاسازیشده
اگر کد همزمان شما یک عملکرد مستقل باشد، برای اهداف اشکالزدایی خود، ممکن است سادهتر باشد که کد همزمان شما را در یک عملکرد منظم نگهدارید، آن را همزمان اجرا کنید، و فقط زمانی که کار کد خود را انجام میدهید، بهطور همزمان آن را اجرا کنید. در این استراتژی، شما شیء Blob یک تابع را به فایلی که تبدیلشده است به یک رشته استفادهشده در روش تابع toString منتقل میکنید. در زمان کامپایل، نام تابع به تابع TypeScript مراجعه میکند، اما در زمان اجرا، همان نام به نسخه جاوا اسکریپت تابع اشاره دارد.
برای اینکه تابع، شروع به کار کند، بهمحض اینکه شیء سازنده در حال تکمیل شدن باشد، باید آن را در پرانتز قرار دهید و پرانتزهای دوگانه را که به تابع فراخوانی شده است اضافه کنید. تابع concurrentFn شروع به خودسازی میکند، بهعنوانمثال:
(function concurrentFn() { …function code… })();
با قرار دادن همه اینها باهم، این کد نسخه رشتهای از یک تابع به نام concurrentFn را به سازنده Blob (با پرانتزهای لازم) منتقل و سپس آن را بهعنوان یک سازنده اجرا میکند:
let fn: string;
fn = “(” + concurrentFn.toString() + “)()”;
b = new Blob([fn], { type: ‘application/javascript’ })
url = window.URL.createObjectURL(b);
w = new Worker(url);
function concurrentFn(): void { …function code… }
بااینوجود، این روش بسیار دور از یک راهحل کامل است زیرا شما از روش سازنده postMessage استفاده کردید. برای آزمایش فیزیکی مناسب عملکردتان، نیاز به یک مکانیزم جایگزین برای انتقال پارامترها به تابع خود دارید. شما همچنین باید اطمینان حاصل کنید از اینکه میتوانید از برگشت مکانیزم به postmessage بهصورت همزمان به کد برابر، آن را تغییر دهید.
ساختار تابع سازنده شما
راهحل من این است که کدی را که میخواهم بهصورت همزمان در داخل یک تابع تودرتو ای که آن را اجرا کنم، بگذارم. سپس من تابع تودرتو خود را از onmessage بهصورت دستی فرامیخوانم، همچنین از ” تابع برابر”. برای دسترسی به عملکرد تابع تودرتو خودم، من تابع برابر خود را به تابع تودرتو خود بازگردانی میکنم، تا کد آن را فراخوانی کنم. درنتیجه، تابع برابر من مثل کد زیر به نظر میرسد. (در عمل، من هرکدام از این کدها را با نوع واقعی پذیرفتهشده آن جایگزین و توسط processData بازگرداندم)
در اینجا یک تابع برابر برای پشتیبانی اشکالزدایی وجود دارد:
function concurrentFn(): (e:MessageEvent) => any
{
this.onmessage = function (e: MessageEvent): void {
(<any>postMessage)(this.processData(e.data));
}
this.processData = (d: any): any => {
…concurrent code to process d..;
return …result of processing…;
}
return this.processData;
}
وقتی میخواهم کد برابر را بهعنوان یک سازنده وب اجرا کنم، من آن را از طریق یک Blob انجام میدهم. وقتی میخواهم اتفاقی را اشکالزدایی کنم، من concurrentFn را فراخوانی میکنم تا تابع processData را که دریافت شده است، بگیرم. در آن بخش، در حالت اشکالزدایی، بهجای فراخوانی onmessage، من تابع پردازش داده را فراخوانی میکنم. این کار باعث میشود مسئلهای در مورد فرمت دادههای منتقلشده، به روش من رخ دهد.
من از یک متغیر Boolean به نام Concurrent برای تشخیص بین زمانی که میخواهم بهصورت همزمان یا اتفاقی آن را پردازش کنم، استفاده میکنم. بهطور ساده برای تعویض بین فراخوانی تابع concurrentFn و شیء سازنده، ابتدا نشانی را برای شیء concurrentFn خود بهعنوان type تعریف میکنم. سپس یک متغیر ثابتی را اعلام میکنم که میتواند یا یکشی سازنده یا تابع concurrentFn را برای من نگه دارد. این کد اینگونه به نظر میرسد. (دوباره، من هر نوع از آن کدها را بهنوعی که به روشهای متداول، منتقلشدهاند را تغییر دادهام):
const Concurrent: boolean = false;
type workerFn = (any) => any;
let w: (Worker | workerFn);
کد معمولی برای نمونهسازی یک شیء سازنده و یا دوبارهسازی روش processData من، مانند لیست 1 به نظر میرسد.
لیست 1: کنترل اجرای کد همزمان یا اتفاقی
if (Concurrent) {
let fn: string;
let b: Blob
fn = “(” + longRunning.toString() + “)()”;
b = new Blob([fn], { type: ‘application/javascript’ })
let url: string;
url = window.URL.createObjectURL(b);
w = new Worker(url);
w.onmessage = (e: MessageEvent) => {processReturnedData(e);};
}
else {
let w = longRunning();
}
بعداً در کد خودم، وقتی میخواهم یک پیام به کد برابر خود میفرستم، من کدی مثل کد زیر را دارم:
if (Concurrent) {
w.postMessage(“A123”);
}
else {
processReturnedData(w(“A123”));
}
مقدار زیادی از کد اضافی است و درنهایت، من یک کلاس WorkerFake ایجاد کردم که دو پارامتر را قبول میکند: تابعی که اجرا میشود و یک مقدار Boolean را نشان میدهد، اگر تابع باید همزمان باهم اجرا شود. هنگامیکه همزمان اجرا میشوند، تابع در کد تکرار میشود که باعث میشود که تابع توسط postMessage که کد اصلی را مورد هدف قرار داده، فراخوانی شود. این روش عمومی است بنابراین شما باید نوع دادههایی را که میخواهید به تابع منتقل کنید را مشخص کنید و همچنین منتظر بازگشت آن باشید. (شما میتوانید آن را در لیست 2 ببینید). کد معمولی که برای این استفاده میشود، اینگونه است:
let wf: WorkerFake<string, Customer>;
wf = new WorkerFake<string, Customer>(false, getCustomer);
wf.onmessage = (e: MessageEvent) => { …code to process Customer object… };
wf.postMessage(“A123”);
function getMockCustomer(id: string): Customer {…code to retrieve Customer…}
البته، اگر توابع برابر من برای اولین بار بهدرستی اجرا شود، هیچکدام از این اتفاقات نمیافتد. این کار میتواند، اتفاق بیفتد.
لیست 2: یک کلاس برای اجرای توابع همزمان یا اتفاقی
class WorkerFake<T,TValue> {
w: Worker;
fnWorker: (T) => TValue;
fnOut: (MessageEvent) => TValue;
constructor(public concurrent: boolean, fn: (any) => any) {
if (concurrent) {
let fns: string;
fns = “onmessage = function (e) { postMessage(” + fn.name + “(e.data)); }; ” + fn.toString();
let b: Blob;
b = new Blob([fns], { type: ‘application/javascript’ })
this.w = new Worker(window.URL.createObjectURL(b));
}
else {
this.fnWorker = fn;
}
}
postMessage(parm: any) {
if (this.concurrent) {
this.w.postMessage(parm);
}
else {
let me: MessageEvent;
me = new MessageEvent(“message”, { data: this.fnWorker(parm) });
this.fnOut(me);
}
}
set onmessage(fno: (MessageEvent) => any) {
if (this.concurrent) {
this.w.onmessage = fno;
}
else {
this.fnOut = fno;
}
}
}
مترجم: آتنا کردی زاد موثق
سوالات و پیشنهادات خود را به صورت دیدگاه مطرح کنید
ارسال دیدگاه