در قسمت قبل توانستیم کدهای متد POST را به طور کامل بنویسیم، حالا زمان تکمیل کدهای کتابخانه و کدنویسی متد های Put و Delete است. برای کد نویسی Put کار بسیار ساده ای را در پیش داریم چرا که هر put یا همان update یک نوع POST به شمار می رود. چرا؟ به دلیل اینکه در درخواست های put هنوز هم داده های جدید را به سمت سرور ارسال می کنیم تا آنجا ثبت شوند، دقیقا کاری که در POST می کردیم! بنابراین:
// Make an HTTP PUT Request easyHTTP.prototype.put = function(url, data, callback) { this.http.open('PUT', url, true); this.http.setRequestHeader('Content-type', 'application/json'); let self = this; this.http.onload = function() { callback(null, self.http.responseText); } this.http.send(JSON.stringify(data)); }
توضیح کد:
برای تست این کد به فایل app.js بروید و تمام کدهای قبلی را کامنت کنید، البته شیء data را نگه دارید چرا که از آن به عنوان داده های ارسالی PUT استفاده خواهیم کرد. سپس کد زیر را بنویسید:
// Update Post http.put('https://jsonplaceholder.typicode.com/posts/5', data, function(err, post) { if(err) { console.log(err); } else { console.log(post); } });
همانطور که می بینید هیچ تفاوتی بین این کد و کدهای جلسه ی قبل وجود ندارد، به جز اینکه url ارسال شده را با id پنج ارسال کرده ایم. در سرور تمرینی JSONPlaceholder این id مشخص می کند که چه resource ای (چه اطلاعاتی، چه پستی و...) ویرایش شود و نتیجه نیز به شکل زیر است که به ما می گوید درخواست به صورت صحیح ارسال شده است:
برای نوشتن کدهای Delete نیز به سادگی می گوییم:
// Make an HTTP DELETE Request easyHTTP.prototype.delete = function(url, callback) { this.http.open('DELETE', url, true); let self = this; this.http.onload = function() { if(self.http.status === 200) { callback(null, 'Post Deleted'); } else { callback('Error: ' + self.http.status); } } this.http.send(); }
کد بالا شباهت زیادی به کد GET دارد. احتمالا از خودتان بپرسید چرا برای Callback مقدار responseText را قرار نداده ام. پاسخ شما این است که در متد Delete چیزی توسط سرور JSONPlaceholder به ما برگردانده نمی شود به جز یک شیء خالی که نشان از حذف شدن اطلاعات دارد بنابراین من رشته ی Post Deleted را به صورت دستی اضافه کرده ام تا بدانیم که درخواست به شکل صحیح ارسال شده است.
مثل همیشه برای تست کدها به app.js می رویم و می گوییم:
// Delete Post http.delete('https://jsonplaceholder.typicode.com/posts/1', function(err, response) { if(err) { console.log(err); } else { console.log(response); } });
مثل درخواست PUT برای درخواست های DELETE نیز باید مشخص کنیم که هدف ما چیست، چه چیزی را می خواهیم حذف کنیم. همچنین نام پارامتری که به تابع callback می دهید هیچ اهمیتی ندارد، من در مثال بالا آن را response گذاشته ام اما هر نام دیگری نیز که باشد باعث مشکل نخواهد شد. پاسخ سرور را نیز در تصویر زیر می بینید:
امیدوارم از تکمیل این کتابخانه لذت برده باشید.
همانطور که قبلا گفته بودم پس از اتمام کدنویسی این کتابخانه آن را به نسخه ی ES6 تغییر می دهیم بنابراین باید به این قول عمل کنم اما قبل از شروع چنین مبحثی باید شما را با برخی از مباحث پایه آشنا کنم. تا اینجای کار ما تنها با شیء قدیمی XMLHttpRequest کار کرده ایم اما برای نسخه ی ES6 می خواهیم از Promise ها و Fetch API و روش های جدیدتر کمک بگیریم بنابراین بهتر است نگاهی به promise ها داشته باشیم.
Promise ها در واقع جایگزین callback ها و نسخه ی جدیدتر آن ها هستند بنابراین از همان مثالی که در جلسه ی callback ها داشتیم (چند جلسه ی قبل) استفاده می کنم:
const posts = [ {title: 'Post One', body: 'This is post one'}, {title: 'Post Two', body: 'This is post two'} ]; function createPost(post, callback) { setTimeout(function() { posts.push(post); callback(); }, 2000); } function getPosts() { setTimeout(function() { let output = ''; posts.forEach(function(post){ output += `<li>${post.title}</li>`; }); document.body.innerHTML = output; }, 1000); } createPost({title: 'Post Three', body: 'This is post three'}, getPosts);
از آنجایی که این کد را با هم و به تفصیل نوشتیم من دوباره آن ها را توضیح نمی دهم، برای اطلاعات بیشتر به قسمت callback ها مراجعه کنید. ما می خواهیم این کد را طوری ویرایش کنیم که به جای callback ها از promise ها استفاده کند. در قدم اول callback را از تابع createPost حذف کنید:
function createPost(post) { setTimeout(function() { posts.push(post); }, 2000); }
برای استفاده از promise ها باید به شکل زیر عمل کنیم:
function createPost(post) { return new Promise(function (resolve, reject) { }); setTimeout(function () { posts.push(post); }, 2000); }
در واقع باید یک نمونه از شیء Promise را return کنیم. این شیء خودش به عنوان پارامتر یک تابع را دریافت می کند که دو پارامتر دارد:
در مرحله ی بعد تابع setTimeout را کات کرده و داخل promise قرار دهید:
function createPost(post) { return new Promise(function (resolve, reject) { setTimeout(function () { posts.push(post); }, 2000); }); }
حالا دقیقا در جایی که قبلا callback را داشتیم، resolve را صدا می زنیم:
function createPost(post) { return new Promise(function (resolve, reject) { setTimeout(function () { posts.push(post); resolve(); }, 2000); }); }
سپس در انتهای این کد به جای پاس دادن getPosts می توانیم از then. استفاده کنیم و getPosts را به آن پاس بدهیم:
const posts = [ { title: 'Post One', body: 'This is post one' }, { title: 'Post Two', body: 'This is post two' } ]; function createPost(post) { return new Promise(function (resolve, reject) { setTimeout(function () { posts.push(post); resolve(); }, 2000); }); } function getPosts() { setTimeout(function () { let output = ''; posts.forEach(function (post) { output += `<li>${post.title}</li>`; }); document.body.innerHTML = output; }, 1000); } createPost({ title: 'Post Three', body: 'This is post three' }).then(getPosts);
Promise ها به همین سادگی قابل درک هستند.
حالا اگر خطایی داشته باشیم می توانیم reject را صدا بزنیم اما در کد بالا که یک کد محلی است هیچ خطایی نداریم بنابراین من یک متغیر به نام error تعریف می کنم تا شرایط خطا را شبیه سازی کنیم:
function createPost(post) { return new Promise(function (resolve, reject) { setTimeout(function () { posts.push(post); const error = true; if (!error) { resolve(); } else { reject('Error: Something went wrong'); } }, 2000); }); }
در واقع با یک شرط if ساده گفته ایم که اگر خطا وجود داشت، کار را متوقف و reject کن اما اگر مشکلی نبود resolve کن (یعنی کدها اجرا بشود). حالا باید به انتهای فایل رفته و پس از then قسمتی به نام catch را نیز بنویسیم:
createPost({ title: 'Post Three', body: 'This is post three' }).then(getPosts).catch(function (err) { console.log(err); });
در واقع then و catch را به هم چسبانده ایم. حالا با ذخیره ی کد بالا به خطای زیر می خوریم:
و اگر متغیر error را روی false بگذاریم دیگر خطایی نخواهیم داشت و کد به درستی کار می کند.
باز هم تکرار می کنم که یادگیری promise ها مهم است چرا که fetch api یک promise را برمی گرداند بنابراین باید با آن ها آشنا باشیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.