{"title":"The Code Ship - Web Development","link":[{"@attributes":{"href":"https:\/\/www.thecodeship.com\/","rel":"alternate"}},{"@attributes":{"href":"https:\/\/www.thecodeship.com\/feeds\/web-development.atom.xml","rel":"self"}}],"id":"https:\/\/www.thecodeship.com\/","updated":"2020-06-11T21:06:00+03:00","entry":[{"title":"Transforming browser HAR logs into an analysis friendly format in Javascript","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/transforming-browser-har-logs-into-analysis-friendly-format\/","rel":"alternate"}},"published":"2020-06-11T21:06:00+03:00","updated":"2020-06-11T21:06:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2020-06-11:\/web-development\/transforming-browser-har-logs-into-analysis-friendly-format\/","summary":"<p>HAR files extracted from HTTP sessions include a lot of useful data that can be utilized for creating custom network and performance audits. Their format though, is not that compatible with analysis tools like Pandas or Tableau out of the box. In this post, I go over a super easy approach towards parsing and transforming them via Objectron in JS.<\/p>","content":"<p>When working on front-end web performance optimizations, there are several tools out there to help in creating performance audits, identifying opportunities and estimating potential gains. <\/p>\n<p>At many times though, I find myself needing a bit more flexibility on building out custom analysis reports from raw data, especially if the analysis involves looking at resources across multiple pages of a user journey and understanding the requests made.<\/p>\n<p>While I wont be delving much into the analysis process in this article, I'll be covering the first step towards enabling that, which is extracting and transforming this data from a browser output to make it consumable by data analysis libraries such as pandas. The <a href=\"https:\/\/github.com\/mena-devs\/objectron\">Objectron<\/a> JS module will makes such task very simple to perform.<\/p>\n<h2>Introducing .HAR files<\/h2>\n<p>Several modern browsers allow the record and export of HTTP sessions via HAR files. The <a href=\"http:\/\/www.softwareishard.com\/blog\/har-12-spec\/\">HAR file specification<\/a> is a standard file used by several HTTP session tools to export captured data. The format is basically a JSON object with a particular field distribution. Some important characteristics of HAR files to note:<\/p>\n<ul>\n<li>They are usually pretty large in size with everything included in them, including request and response bodies<\/li>\n<li>They contain sensitive data including your cookies and whatever is in the requests you're sending or receiving<\/li>\n<li>While HAR is a great format for sharing and reading HTTP session information between different tools, the raw data usually needs some formatting before it's usable in custom analysis scripts, mainly due to it's non-tabular structure and unneeded data.<\/li>\n<\/ul>\n<h3>To extract from a FireFox session<\/h3>\n<ul>\n<li>Start Firefox Developer Tools in Network mode<\/li>\n<li>Perform a set of navigation (Typically, this would be a user journey\/scenario covering multiple pages)<\/li>\n<li>Save the capture by right-clicking on the grid and choosing \"Save all as HAR\"<\/li>\n<li>Export the capture to a HAR file<\/li>\n<\/ul>\n<p><img alt=\"\" src=\"https:\/\/storage.googleapis.com\/thecodeship\/network-tab-ff.png\"><\/p>\n<p>I've created a sample HAR file from a session covering multiple pages, you can <a href=\"https:\/\/storage.googleapis.com\/thecodeship\/menadevs.com.har\">find it here<\/a>.<\/p>\n<p>The request\/response logs we're looking into extracting is in <code>log.entries<\/code><\/p>\n<h2>Extracting and transforming HAR data to CSV<\/h2>\n<p>First step, is to decide which fields, per log item, make sense to keep that will be useful in the analysis and which drop. This, along with flattening the structure into a table will make the contents of the file usable for plugging into analysis libraries such as pandas.<\/p>\n<p>HAR fields that wouldn't be needed for analysis:<\/p>\n<ul>\n<li>Reply content \/ body<\/li>\n<li>Request payloads<\/li>\n<li>Cookie data <\/li>\n<li>Most header values, with a couple of exceptions<\/li>\n<\/ul>\n<p>Fields that can be interesting for a given log entry:<\/p>\n<ul>\n<li>Page id <\/li>\n<li>Request: method, url, httpVersion, headerSize and bodySize<\/li>\n<li>Response: status, content size, content type, cache control<\/li>\n<li>Header values around cache-control, gzip and content-length<\/li>\n<li>Summary of page request and response timings<\/li>\n<\/ul>\n<h3>Extracting data with Objectron<\/h3>\n<p>To extract and flatten the JSON file into a CSV we'd need to:<\/p>\n<ul>\n<li>Loop through the log entries<\/li>\n<li>For each entry, validate that the needed data exists and push it into a flat object. <\/li>\n<li>A log entry will need to be properly validated for having the required data, otherwise to be discarded. E.g. We might only need logs with GET requests, so that check will need to happen<\/li>\n<\/ul>\n<p>Writing a custom script to do all that actually is simple but prone to a lot of repetition and writing several conditions. Such as:<\/p>\n<ul>\n<li>Write multiple if statements to check if the entry object key has a value to begin with<\/li>\n<li>Check if the object key conforms to a specific pattern or value<\/li>\n<li>Write nested loops to extract specific entries in sub arrays such as those of header data, and do the same checks<\/li>\n<li>Manually insert into a flat object with a custom key name to be used for the table header later<\/li>\n<\/ul>\n<p><a href=\"https:\/\/github.com\/mena-devs\/objectron\">Objectron<\/a> makes this task around validation, extraction, and flattening super simple. With a declarative approach, it facilitates comparing a JS object to a generic model\/pattern to validate and extract matches based on regex patterns. Think of it as regex, but for objects!<\/p>\n<p>I won't be getting into all the basics, but you can learn more about the project, get an introduction and intro to other use cases <a href=\"https:\/\/github.com\/mena-devs\/objectron\">here<\/a>.<\/p>\n<p>Back to the use case of a HAR file, lets consider an individual log entry that looks something like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"p\">{<\/span>\n  <span class=\"nt\">&quot;startedDateTime&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;2020-05-26T06:59:37.215Z&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;time&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">179.52900001546368<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;request&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nt\">&quot;method&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;GET&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;url&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;https:\/\/menadevs.com\/directory\/users?name=f&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;httpVersion&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;HTTP\/1.1&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;headers&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Host&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;menadevs.com&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Connection&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;keep-alive&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Upgrade-Insecure-Requests&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;1&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;DNT&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;1&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;User-Agent&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/81.0.4044.138 Safari\/537.36&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Accept&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8,application\/signed-exchange;v=b3;q=0.9&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Sec-Fetch-Site&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;same-origin&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Sec-Fetch-Mode&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;navigate&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Sec-Fetch-User&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;?1&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Sec-Fetch-Dest&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;document&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Referer&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;https:\/\/menadevs.com\/directory\/users?name=b&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Accept-Encoding&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;gzip, deflate, br&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Accept-Language&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;en-US,en;q=0.9,ar;q=0.8,es;q=0.7&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Cookie&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;_mena_devs_session=180300e84e30e891209258840d29d9bd; _ga=GA1.2.320033917.1590476331; _gid=GA1.2.1421047438.1590476331; _gat=1&quot;<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">],<\/span>\n    <span class=\"nt\">&quot;queryString&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;name&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;f&quot;<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">],<\/span>\n    <span class=\"nt\">&quot;cookies&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;_mena_devs_session&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;180300e84e30e891209258840d29d9bd&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;expires&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;httpOnly&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;secure&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;_ga&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;GA1.2.320033917.1590476331&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;expires&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;httpOnly&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;secure&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;_gid&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;GA1.2.1421047438.1590476331&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;expires&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;httpOnly&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;secure&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;_gat&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;1&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;expires&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">null<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;httpOnly&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;secure&quot;<\/span><span class=\"p\">:<\/span> <span class=\"kc\">false<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">],<\/span>\n    <span class=\"nt\">&quot;headersSize&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">766<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;bodySize&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">0<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"nt\">&quot;response&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nt\">&quot;status&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;statusText&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;OK&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;httpVersion&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;HTTP\/1.1&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;headers&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Server&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;nginx\/1.14.0 (Ubuntu)&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Date&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Tue, 26 May 2020 06:59:37 GMT&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Content-Type&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;text\/html; charset=utf-8&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Transfer-Encoding&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;chunked&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Connection&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;keep-alive&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;ETag&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;W\/\\&quot;9dd057e36d9f985cec4fd1f68809d3c5\\&quot;&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Cache-Control&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;max-age=0, private, must-revalidate&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Request-Id&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;2ca2f8db-3de2-4bb7-a768-f7286368b67b&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Runtime&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;0.031040&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Strict-Transport-Security&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;max-age=631139040&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Content-Type-Options&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;nosniff&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Frame-Options&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;SAMEORIGIN&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Permitted-Cross-Domain-Policies&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;none&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-XSS-Protection&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;1; mode=block&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;X-Cache-Status&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;MISS&quot;<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"p\">{<\/span>\n        <span class=\"nt\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;Content-Encoding&quot;<\/span><span class=\"p\">,<\/span>\n        <span class=\"nt\">&quot;value&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;gzip&quot;<\/span>\n      <span class=\"p\">}<\/span>\n    <span class=\"p\">],<\/span>\n    <span class=\"nt\">&quot;cookies&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[],<\/span>\n    <span class=\"nt\">&quot;content&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nt\">&quot;size&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">14011<\/span><span class=\"p\">,<\/span>\n      <span class=\"nt\">&quot;mimeType&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;text\/html&quot;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nt\">&quot;compression&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">9960<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nt\">&quot;redirectURL&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;headersSize&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">576<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;bodySize&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">4051<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;_transferSize&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">4627<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"nt\">&quot;cache&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{},<\/span>\n  <span class=\"nt\">&quot;timings&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nt\">&quot;blocked&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">2.917000008152798<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;dns&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">-1<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;ssl&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">-1<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;connect&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">-1<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;send&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">0.125<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;wait&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">173.83599999024347<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;receive&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">2.6510000170674175<\/span><span class=\"p\">,<\/span>\n    <span class=\"nt\">&quot;_blocked_queueing&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mf\">1.6790000081527978<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"nt\">&quot;serverIPAddress&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;188.166.50.85&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;_initiator&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nt\">&quot;type&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;other&quot;<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"nt\">&quot;_priority&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;VeryHigh&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;_resourceType&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;document&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;connection&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;658445&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"nt\">&quot;pageref&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;page_7&quot;<\/span>\n<span class=\"p\">}<\/span><span class=\"err\">,<\/span>\n<\/pre><\/div>\n\n\n<p>The model to parse, extract and flatten the data would look something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span>  <span class=\"kr\">const<\/span> <span class=\"nx\">entryPattern<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">pageref<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;pageRef&gt;.*)\/<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">startedDateTime<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;startedDateTime&gt;.*)\/<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">request<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">method<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;requestMethod&gt;GET|POST)\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">url<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;requestUrl&gt;[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&amp;\/\/=]*))\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">httpVersion<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;requestHttpVersion&gt;.*)\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">headersSize<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^(?&lt;requestHeaderSize&gt;\\-?(\\d+\\.?\\d*|\\d*\\.?\\d+))$\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">bodySize<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^(?&lt;requestHeaderSize&gt;\\-?(\\d+\\.?\\d*|\\d*\\.?\\d+))$\/<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">response<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">status<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^(?&lt;responseStatus&gt;[0-9]{3})\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">content<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">size<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^(?&lt;responseContentSize&gt;\\-?(\\d+\\.?\\d*|\\d*\\.?\\d+))$\/<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">},<\/span>\n      <span class=\"nx\">headers<\/span><span class=\"o\">:<\/span> <span class=\"p\">[<\/span>\n        <span class=\"p\">{<\/span> <span class=\"nx\">name<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^content-type$\/i<\/span><span class=\"p\">,<\/span> <span class=\"nx\">value<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;responseContentType&gt;.*)\/<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span> <span class=\"nx\">name<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^content-length$\/i<\/span><span class=\"p\">,<\/span> <span class=\"nx\">value<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;responseContentLength&gt;.*)\/<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span> <span class=\"nx\">name<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^cache-control$\/i<\/span><span class=\"p\">,<\/span> <span class=\"nx\">value<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/(?&lt;responseCacheControl&gt;.*)\/<\/span> <span class=\"p\">},<\/span>\n      <span class=\"p\">]<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">timings<\/span><span class=\"o\">:<\/span> <span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"nx\">val<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">time<\/span><span class=\"o\">:<\/span> <span class=\"sr\">\/^(?&lt;time&gt;\\-?(\\d+\\.?\\d*|\\d*\\.?\\d+))$\/<\/span>\n  <span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>The above pattern is pretty much all the code we'd need to parse an entry! <\/p>\n<p>In the above defined model we can:<\/p>\n<ul>\n<li>Declaratively mimic the structure of the object we're comparing against. From there, Objectron will recursively access, validate and extract the matching keys and values.<\/li>\n<li>Define static values to match against keys and values<\/li>\n<li>Define regex patterns for keys and values, with optional named groups.<\/li>\n<\/ul>\n<p>Passing in the harLogEntry and pattern to the Objectron match function:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kr\">const<\/span> <span class=\"nx\">match<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">require<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;@menadevs\/objectron&#39;<\/span><span class=\"p\">);<\/span>\n\n<span class=\"kr\">const<\/span> <span class=\"nx\">result<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">match<\/span><span class=\"p\">(<\/span>\n  <span class=\"nx\">harEntry<\/span><span class=\"p\">,<\/span> <span class=\"nx\">entryPattern<\/span>\n<span class=\"p\">);<\/span>\n<\/pre><\/div>\n\n\n<p>Would return a result object that looks like:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"p\">{<\/span>\n  <span class=\"nx\">match<\/span><span class=\"o\">:<\/span> <span class=\"kc\">true<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">total<\/span><span class=\"o\">:<\/span> <span class=\"mi\">15<\/span><span class=\"p\">,<\/span>\n  <span class=\"nx\">matches<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">pageref<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;page_7&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">startedDateTime<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;2020-05-26T06:59:37.215Z&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">request<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">method<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;GET&#39;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">url<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;https:\/\/menadevs.com\/directory\/users?name=f&#39;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">httpVersion<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;HTTP\/1.1&#39;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">headersSize<\/span><span class=\"o\">:<\/span> <span class=\"mi\">766<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">bodySize<\/span><span class=\"o\">:<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">response<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">status<\/span><span class=\"o\">:<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">content<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">size<\/span><span class=\"o\">:<\/span> <span class=\"mi\">14011<\/span> <span class=\"p\">},<\/span>\n      <span class=\"nx\">headers<\/span><span class=\"o\">:<\/span> <span class=\"p\">[<\/span>\n        <span class=\"p\">{<\/span> <span class=\"nx\">name<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;Content-Type&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nx\">value<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;text\/html; charset=utf-8&#39;<\/span> <span class=\"p\">},<\/span>\n        <span class=\"p\">{<\/span>\n          <span class=\"nx\">name<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;Cache-Control&#39;<\/span><span class=\"p\">,<\/span>\n          <span class=\"nx\">value<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;max-age=0, private, must-revalidate&#39;<\/span>\n        <span class=\"p\">}<\/span>\n      <span class=\"p\">]<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">timings<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">blocked<\/span><span class=\"o\">:<\/span> <span class=\"mf\">2.917000008152798<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">dns<\/span><span class=\"o\">:<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">ssl<\/span><span class=\"o\">:<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">connect<\/span><span class=\"o\">:<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">send<\/span><span class=\"o\">:<\/span> <span class=\"mf\">0.125<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">wait<\/span><span class=\"o\">:<\/span> <span class=\"mf\">173.83599999024347<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">receive<\/span><span class=\"o\">:<\/span> <span class=\"mf\">2.6510000170674175<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">_blocked_queueing<\/span><span class=\"o\">:<\/span> <span class=\"mf\">1.6790000081527978<\/span>\n    <span class=\"p\">},<\/span>\n    <span class=\"nx\">time<\/span><span class=\"o\">:<\/span> <span class=\"mf\">179.52900001546368<\/span>\n  <span class=\"p\">},<\/span>\n  <span class=\"nx\">groups<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">pageRef<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;page_7&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">startedDateTime<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;2020-05-26T06:59:37.215Z&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">requestMethod<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;GET&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">requestUrl<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;menadevs.com\/directory\/users?name=f&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">requestHttpVersion<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;HTTP\/1.1&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">requestHeaderSize<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;0&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">responseStatus<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;200&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">responseContentSize<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;14011&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">responseContentType<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;text\/html; charset=utf-8&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">responseCacheControl<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;max-age=0, private, must-revalidate&#39;<\/span><span class=\"p\">,<\/span>\n    <span class=\"nx\">time<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;179.52900001546368&#39;<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>All the named capturing groups have been added to a flat groups object, based on the values we've selected via the model. In the next step, the groups result object, will be extracted and transformed into a row entry in the final CSV file.<\/p>\n<p>We could also be inserting additional values into our row which have been captured, such as the timings object. The values of the timings object aren't showing in the groups result because we didn't really chose a named group for them, but instead assigned a wildcard via <code>timings: (val) =&gt; val<\/code> in the model to indicate that we want to extract everything from that sub-object.<\/p>\n<h2>Putting it all together<\/h2>\n<p>From that point on, the overall task is pretty simple. Loop over <code>log.entries<\/code> and test for matches. On Each match, combine the matched groups with the timings result and create a new flat row into a list to be exported to CSV or a similar tabular format later.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kr\">const<\/span> <span class=\"nx\">csvOutputPath<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">;<\/span>\n<span class=\"kd\">let<\/span> <span class=\"nx\">flatEntries<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n\n<span class=\"nx\">harFile<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">.<\/span><span class=\"nx\">entries<\/span><span class=\"p\">.<\/span><span class=\"nx\">forEach<\/span><span class=\"p\">((<\/span><span class=\"nx\">entry<\/span><span class=\"p\">,<\/span> <span class=\"nx\">entryIndex<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"kr\">const<\/span> <span class=\"nx\">currentEntry<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">match<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">entry<\/span><span class=\"p\">,<\/span> <span class=\"nx\">entryPattern<\/span>\n  <span class=\"p\">);<\/span>\n\n  <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"nx\">currentEntry<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"kr\">const<\/span> <span class=\"nx\">flatEntry<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n      <span class=\"p\">...<\/span><span class=\"nx\">currentEntry<\/span><span class=\"p\">.<\/span><span class=\"nx\">groups<\/span><span class=\"p\">,<\/span>\n      <span class=\"p\">...<\/span><span class=\"nx\">currentEntry<\/span><span class=\"p\">.<\/span><span class=\"nx\">matches<\/span><span class=\"p\">.<\/span><span class=\"nx\">timings<\/span>\n    <span class=\"p\">};<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">entryIndex<\/span> <span class=\"o\">===<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">flatEntries<\/span><span class=\"p\">.<\/span><span class=\"nx\">push<\/span><span class=\"p\">(<\/span><span class=\"nb\">Object<\/span><span class=\"p\">.<\/span><span class=\"nx\">keys<\/span><span class=\"p\">(<\/span><span class=\"nx\">flatEntry<\/span><span class=\"p\">));<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">flatEntries<\/span><span class=\"p\">.<\/span><span class=\"nx\">push<\/span><span class=\"p\">(<\/span><span class=\"nb\">Object<\/span><span class=\"p\">.<\/span><span class=\"nx\">values<\/span><span class=\"p\">(<\/span><span class=\"nx\">flatEntry<\/span><span class=\"p\">));<\/span>\n  <span class=\"p\">}<\/span>\n <span class=\"p\">});<\/span>\n\n <span class=\"nx\">stringify<\/span><span class=\"p\">(<\/span><span class=\"nx\">flatEntries<\/span><span class=\"p\">,<\/span> <span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">,<\/span> <span class=\"nx\">output<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n   <span class=\"nx\">fs<\/span><span class=\"p\">.<\/span><span class=\"nx\">writeFile<\/span><span class=\"p\">(<\/span><span class=\"nx\">csvOutputath<\/span><span class=\"p\">,<\/span> <span class=\"nx\">output<\/span><span class=\"p\">,<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n     <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">)<\/span> <span class=\"k\">return<\/span> <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">);<\/span>\n   <span class=\"p\">});<\/span>\n <span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p>A resulting CSV can look something like <a href=\"https:\/\/storage.googleapis.com\/thecodeship\/menadevs-har-logs.csv\">this<\/a>. <\/p>\n<p>I started building a simple CLI utility which pretty much follows this approach. You can check it out <a href=\"https:\/\/github.com\/google\/har2csv\">here<\/a>.<\/p>\n<h2>Running an analysis<\/h2>\n<p>From this point it becomes trivial to load this data into a Jupyter notebook or similar tools. <\/p>\n<p>One interesting exercise I'd do with HAR data can be around recording an HTTP session that goes through multiple pages of the conversion funnel of an online purchase. Analyzing this dataset can be very useful to understand the number of times the same resource are being requested over and over again across pages, whether their requests are properly cached, pre-fetched or pre-connected to. This could uncover multiple ideas for optimization opportunities on resources utilized across multiple pages.<\/p>\n<p>In an upcoming article, I'll be going through a full exercise around uncovering optimization opportunities with such data. In the meantime, I just kicked that off with a Jupyter notebook and a couple of basic queries on a HAR CSV file to get started. You can check it out <a href=\"https:\/\/github.com\/aymanfarhat\/har-analysis-notebook-example\/blob\/master\/HAR%20File%20Analysis.ipynb\">here<\/a>.<\/p>\n<h2>That's all folks!<\/h2>\n<p>This was a quick intro to utilizing the Objectron module for parsing out HAR files into something a bit more useful. I hope you found it useful, would love to hear your thoughts! Looking forward to seeing you next time as we build on what we tried out today into a full analysis!<\/p>","category":[{"@attributes":{"term":"har"}},{"@attributes":{"term":"browsers"}},{"@attributes":{"term":"logs"}},{"@attributes":{"term":"http"}},{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"objectron"}},{"@attributes":{"term":"nodejs"}},{"@attributes":{"term":"performance"}}]},{"title":"A guide to Service Workers - pitfalls and best practices","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/guide-service-worker-pitfalls-best-practices\/","rel":"alternate"}},"published":"2020-05-10T11:00:00+03:00","updated":"2020-05-10T11:00:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2020-05-10:\/web-development\/guide-service-worker-pitfalls-best-practices\/","summary":"<p>Service workers is one of the most useful features that came to modern browsers. Implementation can be quite tricky though and prone to a lot of issues that could slip into production. I'll be discussing my set of tips and best practices on the subject.<\/p>","content":"<p>Service worker is one of the most useful features that came to modern browsers. I've always enjoyed the features they can bring into web apps such as caching assets, and enabling offline user experiences. Implementation can be quite tricky though and prone to a lot of issues that could easily slip into production if not tested properly.<\/p>\n<p>In this post, I'll be discussing my set of \"tips from the trenches\" that I've documented along the way while building out and auditing several service worker implementations.<\/p>\n<h2>Make sure to set the right scope for your service worker<\/h2>\n<p>One of the early mistakes that one might make, is to include the service worker script into some sub-directory without specifying a scope. In a typical web app, adding JS related files into a specific sub-directory sounds pretty natural. For Service Worker files, this can be problematic by default since scope of the service worker is defined by its location relative to the web root of the web app.<\/p>\n<p>This means, if you put your script in a <code>\/assets\/js<\/code> directory its scope is limited to the <code>\/assets\/js<\/code>. In that case, the service worker can only handle or intercept requests through <code>examplesite.com\/assets\/js\/<\/code>, and completely ignore other requests such as those going through <code>examplesite.com<\/code> or  <code>examplesite.com\/news\/<\/code> for example. <\/p>\n<p>If you want the service worker to handle any request coming through any part of the site, you have have two options:<\/p>\n<ul>\n<li>Place the service worker file on the web root directory, which would set its scope to cover the whole site by default.<\/li>\n<li>Explicitly define the service worker's scope when registering it:<\/li>\n<\/ul>\n<div class=\"highlight\"><pre><span><\/span>  <span class=\"nx\">navigator<\/span><span class=\"p\">.<\/span><span class=\"nx\">serviceWorker<\/span><span class=\"p\">.<\/span><span class=\"nx\">register<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;\/assets\/js\/sw.js&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">scope<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;\/&#39;<\/span>\n  <span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<h2>Delay registering a service worker until after a web app's load event fire<\/h2>\n<p>When a page is loading, all resources such as bandwidth and CPU time, should be prioritized to serving the minimum set of critical resources needed to display an interactive page to the user. \nThis is even more critical in a scenario such as a first time mobile browser accessing a page, not  running over a flaky 3G network. You wouldn't want the service worker to be competing on resources while the page is being rendered.<\/p>\n<p>It's recommended to always delay registering a service worker until the web app has loaded properly. A general rule of thumb would be register it on the window <code>load<\/code> event, example:<\/p>\n<div class=\"highlight\"><pre><span><\/span>  <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;serviceWorker&#39;<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">navigator<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nb\">window<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;load&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">()<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"nx\">navigator<\/span><span class=\"p\">.<\/span><span class=\"nx\">serviceWorker<\/span><span class=\"p\">.<\/span><span class=\"nx\">register<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;sw.js&#39;<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">});<\/span>\n  <span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>The above applies to many cases, but the right time to start the registration would highly depend on the web app and how it works. If you're using a framework that needs additional setup after the page has loaded, you might want to check for framework specific events that signal that the work is done.<\/p>\n<p>For more information on optimizing resource usage on page load, I would suggest checking out <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/primers\/service-workers\/registration#a_users_first_visit\">a user's first journey<\/a>.<\/p>\n<h2>Don't worry about a service worker caching itself<\/h2>\n<p>If a service worker is set to intercept and cache all requests, one might worry that an older service worker could end up serving a cached version of itself rather serving and registering a new one.<\/p>\n<p>It turns out, a service worker's fetch event handler is not triggered when the page requests a service worker script to register or update. For example, when you call <code>navigator.serviceWorker.register('sw.js)<\/code> the request for <code>sw.js<\/code> isn't intercepted by any service worker's fetch event handler.<\/p>\n<p>For reference, you might want to look at the specification of <a href=\"https:\/\/w3c.github.io\/ServiceWorker\/#update-algorithm\">service worker's update algorithm<\/a>.<\/p>\n<h2>A service worker's cache is accessible from the main thread<\/h2>\n<p>In many cases, you might want to manage some aspects related to the app shell or content cache from within the main thread based on certain user interactions.<\/p>\n<p>The good news is that the service worker's cache is accessible from the main thread via <code>window.caches<\/code> just like you'd use <code>self.caches<\/code> within the service worker's code. <\/p>\n<p>This <a href=\"https:\/\/googlechrome.github.io\/samples\/service-worker\/window-caches\/\">snippet<\/a>, shows an example of that.<\/p>\n<h2>Use a library for messaging<\/h2>\n<p>As you might have noticed, the service worker can't access the main thread and its related resources, such as DOM and Window object. <\/p>\n<p>To communicate with the main thread, the service worker uses <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/postMessage\">postMessage<\/a> to send data and receive data.<\/p>\n<p>You might want to reduce the overall complexity of postMessage by using a wrapper library for that such as <a href=\"https:\/\/github.com\/bevacqua\/swivel\">Swivel<\/a><\/p>\n<h2>Clone the fetch response stream when it needs to be consumed more than once<\/h2>\n<p>As an optimization for efficient memory usage, <code>fetch<\/code> gets the request\/response body as a stream that doesn't get buffered into memory and can be consumed only once. This could get complicated when you're trying to read the response stream multiple times, such as pushing the result into the cache and returning the response back to the client. <\/p>\n<p>The solution in such case would be to clone the response stream. Below is an example of a cache first strategy using that approach. Notice how on line 6 the response object is cloned before adding it into the cache while the original response stream gets returned to the client.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">self<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">respondWith<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">caches<\/span><span class=\"p\">.<\/span><span class=\"nx\">open<\/span><span class=\"p\">(<\/span><span class=\"nx\">CACHE<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">cache<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">||<\/span> <span class=\"nx\">fetch<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">put<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">,<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">clone<\/span><span class=\"p\">());<\/span>\n          <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">});<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p>I highly recommend checking out the article on <a href=\"https:\/\/jakearchibald.com\/2014\/reading-responses\/\">what happens when you read a response?<\/a> explaining this concept in detail.<\/p>\n<h2>Avoid adding a \"pass-through\" fetch handler<\/h2>\n<p>If you're registering a service worker yet have no need to intercept and cache any request, you might feel you should define \"pass-through\" fetch event listener such as:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">self<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"nx\">event<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">respondWith<\/span><span class=\"p\">(<\/span><span class=\"nx\">fetch<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">));<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p>While this pass-through won't affect the behavior of the web app, it can introduce a performance overhead due to several reasons.<\/p>\n<ol>\n<li>\n<p>It adds a latency hit for every single network request made, mainly due to calling respondWith and fetch unnecessarily. <\/p>\n<\/li>\n<li>\n<p>If the service worker is not already running, there is usually an overhead in starting it up. Many browsers optimize on that by not starting up the service worker on network requests unless a fetch handler is defined. Registering a fetch handler that doesn't do anything leads to consuming resources on the user's device unnecessarily.<\/p>\n<\/li>\n<\/ol>\n<h2>Avoid caching bad responses by properly handling them in fetch<\/h2>\n<p>A fetch promise always returns a response object for the given request, which contains the status code of the response. This is true for all responses including those containing error status codes (such as 4xx and 5xx).<\/p>\n<p>It's important to keep that in mind when implementing caching strategies so that you don't end up caching bad responses. <\/p>\n<p>While the below cache-first strategy example would work, it's missing a very important detail around handling the status of fresh responses from the server. It will be caching pretty much any reply with any status!<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">self<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">respondWith<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">caches<\/span><span class=\"p\">.<\/span><span class=\"nx\">open<\/span><span class=\"p\">(<\/span><span class=\"nx\">CACHE<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">cache<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">||<\/span> <span class=\"nx\">fetch<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">put<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">,<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">clone<\/span><span class=\"p\">());<\/span>\n          <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">})<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p>Always keep in mind that HTTP responses with errors (such as 4xx and 5xx) won't be throwing any exception. They will need to be handled in the <code>.then<\/code> clause by checking the status of the reply. An improvement that can be done over the example above would be to check the response status and only cache successful responses.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">self<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">respondWith<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">caches<\/span><span class=\"p\">.<\/span><span class=\"nx\">open<\/span><span class=\"p\">(<\/span><span class=\"nx\">CACHE<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">cache<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">||<\/span> <span class=\"nx\">fetch<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">status<\/span> <span class=\"o\">===<\/span> <span class=\"mi\">200<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">put<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">,<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">clone<\/span><span class=\"p\">());<\/span>\n          <span class=\"p\">}<\/span>\n\n          <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">})<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p>The only case where an exception is thrown by fetch is when the request completely fails due to network failure, such as being offline. You could take such an opportunity to handle the exception and serve a custom reply on the resource in that case. Example below:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kr\">const<\/span> <span class=\"nx\">offlineHTML<\/span> <span class=\"o\">=<\/span> <span class=\"sb\">`&lt;h1&gt;You&#39;re offline!&lt;\/h1&gt;`<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nx\">self<\/span><span class=\"p\">.<\/span><span class=\"nx\">addEventListener<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;fetch&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n  <span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">respondWith<\/span><span class=\"p\">(<\/span>\n    <span class=\"nx\">caches<\/span><span class=\"p\">.<\/span><span class=\"nx\">open<\/span><span class=\"p\">(<\/span><span class=\"nx\">CACHE<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">cache<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">return<\/span> <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span> <span class=\"o\">||<\/span> <span class=\"nx\">fetch<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">).<\/span><span class=\"nx\">then<\/span><span class=\"p\">((<\/span><span class=\"nx\">response<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">status<\/span> <span class=\"o\">===<\/span> <span class=\"mi\">200<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">cache<\/span><span class=\"p\">.<\/span><span class=\"nx\">put<\/span><span class=\"p\">(<\/span><span class=\"nx\">event<\/span><span class=\"p\">.<\/span><span class=\"nx\">request<\/span><span class=\"p\">,<\/span> <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">clone<\/span><span class=\"p\">());<\/span>\n          <span class=\"p\">}<\/span>\n\n          <span class=\"k\">return<\/span> <span class=\"nx\">response<\/span><span class=\"p\">;<\/span>\n        <span class=\"p\">}).<\/span><span class=\"k\">catch<\/span><span class=\"p\">(()<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"p\">{<\/span>\n          <span class=\"k\">return<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">Response<\/span><span class=\"p\">(<\/span><span class=\"nx\">offlineHTML<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">headers<\/span><span class=\"o\">:<\/span> <span class=\"p\">{<\/span>\n              <span class=\"s1\">&#39;Content-Type&#39;<\/span><span class=\"o\">:<\/span> <span class=\"s1\">&#39;text\/html;charset=utf-8&#39;<\/span>\n            <span class=\"p\">}<\/span>\n          <span class=\"p\">});<\/span>\n        <span class=\"p\">});<\/span>\n      <span class=\"p\">});<\/span>\n    <span class=\"p\">})<\/span>\n  <span class=\"p\">);<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<p><strong>Note:<\/strong> 2 crucial details are intentionally missing from the above examples to keep things simple for illustration purposes:<\/p>\n<ol>\n<li>Route and file type checking on the requested resource, which I'm assuming are HTML documents<\/li>\n<li>Checking and setting cache expiry<\/li>\n<\/ol>\n<p>Hence, <strong>I wouldn't advise copy\/pasting the above code into production as is.<\/strong><\/p>\n<h2>Setting web server cache-control policy the for service worker file<\/h2>\n<p>This issue is becoming less of a concern over time as recent major browser versions are shipping changes, implementing an <a href=\"https:\/\/github.com\/w3c\/ServiceWorker\/issues\/893\">update on the default service worker file caching behavior<\/a>, which now gets the browser to ignore the HTTP cache directive when checking for updates on the service worker script.<\/p>\n<p>For supporting older browser version, you might still want to make sure that the request to <code>sw.js<\/code> isn't cached by the browser. This can be simply done by setting <code>Cache-control: no-cache<\/code> and <code>max-age: 0<\/code> on the service worker file in your web server. In nginx, the configuration can looks something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"k\">location<\/span> <span class=\"o\">~*<\/span> <span class=\"p\">(<\/span><span class=\"n\">sw<\/span><span class=\"err\">\\<\/span><span class=\"p\">.<\/span><span class=\"n\">js<\/span><span class=\"p\">)<\/span><span class=\"err\">$<\/span> <span class=\"err\">{<\/span>\n    <span class=\"n\">add_header<\/span> <span class=\"s1\">&#39;Cache-Control&#39;<\/span> <span class=\"s1\">&#39;no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0&#39;<\/span><span class=\"p\">;<\/span>\n    <span class=\"n\">expires<\/span> <span class=\"k\">off<\/span><span class=\"p\">;<\/span>\n    <span class=\"n\">proxy_no_cache<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n<span class=\"err\">}<\/span>\n<\/pre><\/div>\n\n\n<p>You can later test out the service worker's cache-control setting via: <code>curl -X GET -I http:\/\/yourwebsitehere.xyz\/sw.js<\/code><\/p>\n<h1>Evaluate caching strategy examples and never copy paste them directly<\/h1>\n<p>Looking at examples online is great, but always make sure to learn something from them over copy pasting the example into your code (This is recommended for the code shared here too). <\/p>\n<p>While this rule applies to any piece of code you're writing, it can be particularly dangerous with caching strategies, even if some might seem production ready.<\/p>\n<p>This is because every implementation will highly depend on the nature of the web app, how it behaves and the business logic involved. Here is a small checklist I keep in mind when reviewing a service worker code example:<\/p>\n<ul>\n<li>Check for routing and file type patterns, do they make sense?<\/li>\n<li>How does it implement cache expiry logic? Does that apply to my requirements?<\/li>\n<li>Cache TTL, is it uniform for all caches or specific to certain file types\/routes ?<\/li>\n<li>Which <a href=\"https:\/\/developers.google.com\/web\/fundamentals\/instant-and-offline\/offline-cookbook\">caching strategies<\/a> does it apply? For which resource types \/ routes ?<\/li>\n<\/ul>\n<p>I would go over the above criteria and evaluate how each one of those would apply\/make sense within the specific use case and modify accordingly.<\/p>\n<h1>You might not need to build a service worker from scratch<\/h1>\n<p>Finally, when going for production, you might not really need to build out the service worker from scratch. Libraries like <a href=\"https:\/\/developers.google.com\/web\/tools\/workbox\">Workbox<\/a> can provide several helper functions and wrappers out of the box for complex implementations which could save you several hours of troubleshooting, testing and headache.<\/p>\n<p>If you're just starting out, I would still recommend playing around with building a couple of vanilla implementations in order to get a grip at understanding how service workers work before jumping into using a library though.<\/p>\n<h1>Did I miss anything?<\/h1>\n<p>I would love to hear more about your tips on service worker implementation that I might have missed in the comments below. Would also appreciate any other feedback you might have!<\/p>","category":[{"@attributes":{"term":"service-workers"}},{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"best"}},{"@attributes":{"term":"practices"}},{"@attributes":{"term":"advice"}},{"@attributes":{"term":"pitfalls"}},{"@attributes":{"term":"tips"}}]},{"title":"A guide on implementing free SSL certificate on Nginx using Let's Encrypt","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/guide-implementing-free-ssl-certificate-nginx-lets-encrypt\/","rel":"alternate"}},"published":"2017-05-07T17:35:00+03:00","updated":"2017-05-07T17:35:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2017-05-07:\/web-development\/guide-implementing-free-ssl-certificate-nginx-lets-encrypt\/","summary":"<p>If you're reading this article, I'm assuming that you're already sold on the numerous benefits of securing your website with an SSL certificate. Wether it's for encrypting data transfers, establishing more credibility or even improving your <a href=\"http:\/\/searchengineland.com\/googles-gary-illyes-https-may-break-ties-between-two-equal-search-results-230691\">SEO ranking<\/a> (yes you heard it right) it's now easier than ever to obtain \u2026<\/p>","content":"<p>If you're reading this article, I'm assuming that you're already sold on the numerous benefits of securing your website with an SSL certificate. Wether it's for encrypting data transfers, establishing more credibility or even improving your <a href=\"http:\/\/searchengineland.com\/googles-gary-illyes-https-may-break-ties-between-two-equal-search-results-230691\">SEO ranking<\/a> (yes you heard it right) it's now easier than ever to obtain an SSL certificate for that.<\/p>\n<p>Traditionally, an SSL certificate costs anywhere from $30 to $100 a year depending on where you're hosting it. It has always been a struggle to find a truly reliable authority for obtaining a free SSL.<\/p>\n<p>Luckily, the Linux Foundation decided to step up and solve this problem by creating <a href=\"https:\/\/letsencrypt.org\/about\/\">Let's Encyrpt<\/a>, a free, automated, and open CA (Certificate Authority) for everyone. With Let's Encrypt, you can now <a href=\"https:\/\/blog.codinghorror.com\/lets-encrypt-everything\/\">encrypt everything<\/a> for free.<\/p>\n<p>Let's Encrypt is a fantastic service, but with the vast amount of 3rd party tutorials out there and so many changes that happened with the service itself through the different phases, I found most of the content either confusing or just obsolete. In the end, and after a lot of research from here and there, I managed to get it working.<\/p>\n<p>The process itself turned out to be pretty simple, so I've summarised a full tutorial on how to do it on Ubuntu 16.04 with Nginx in 4 straightforward steps. The steps should be doable under other Linux flavours or Ubuntu versions, with small differences in the commands.<\/p>\n<h2>Some background about Let's Encrypt<\/h2>\n<p>Before diving into the process I want to highlight a couple of details on the implementation. <\/p>\n<p>The basic idea for identifying domain control in order to issue or renew certificates is to serve letsencrypt \"ACME Challenges\" from your web server.<\/p>\n<p>There are mainly 2 modes of operation that you can setup your certificate on:<\/p>\n<ol>\n<li>\n<p><strong>Standalone<\/strong><\/p>\n<p>This mode is used to obtain a certificate if you don't want to use or   already have a web server setup. It does not rely on the web server     software (such as Nginx) to identify the domain and obtain a    certificate. In that case, letsencrypt would have to bind to port 80    and serve the challenges.<\/p>\n<p>More details about stand alone mode <a href=\"https:\/\/certbot.eff.org\/docs\/using.html#standalone\">here<\/a><\/p>\n<\/li>\n<li>\n<p><strong>Webroot<\/strong><\/p>\n<p>This mode allows you to serve the challenges from your locally  running web server (such as Nginx) from a known folder. You don't   need to stop the server during the issuance or renewal process while    it's already bound to port 80. More details will have to included   related to your project web root paths.<\/p>\n<p>The great thing about this mode is that it's straightforward to setup   wether you have an existing web server installed or a installing a  new one.<\/p>\n<p>More details about Webroot mode <a href=\"https:\/\/certbot.eff.org\/docs\/using.html#webroot\">here<\/a><\/p>\n<\/li>\n<\/ol>\n<p>For more information on how Let's Encrypt works, you check out this <a href=\"https:\/\/letsencrypt.org\/how-it-works\/\">link<\/a><\/p>\n<p>In this guide I'll be going with the webroot mode with Nginx, so let's dive in!<\/p>\n<h2>Step 1: Setup and prepare Nginx<\/h2>\n<p>First of all, we'll install and setup all the files related to Nginx and the base configuration, if you don't have a web server installed yet now is the time to do so.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">sudo<\/span> <span class=\"n\">apt<\/span><span class=\"o\">-<\/span><span class=\"k\">get<\/span> <span class=\"n\">install<\/span> <span class=\"n\">nginx<\/span>\n<\/pre><\/div>\n\n\n<p>Now that we have Nginx, lets setup 2 main config files that can be included into our main Nginx config later. Optionally, you could jusr include those sections directly into your main Nginx site config file but it's more flexible to separate and include them on demand. The files we'll be creating below can be re-used with multiple Nginx site configurations.<\/p>\n<h3>Let's encrypt challenge<\/h3>\n<p>As mentioned earlier, we need to create a hidden directory and configure our web server to serve the challenges from it, in order for the certificate authority to validate the domain.<\/p>\n<p>Let's create the file<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"n\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"n\">letsencrypt<\/span><span class=\"p\">.<\/span><span class=\"n\">conf<\/span>\n<\/pre><\/div>\n\n\n<p>and add the following configuration into it<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"k\">location<\/span> <span class=\"o\">^~<\/span> <span class=\"o\">\/<\/span><span class=\"p\">.<\/span><span class=\"n\">well<\/span><span class=\"o\">-<\/span><span class=\"n\">known<\/span><span class=\"o\">\/<\/span><span class=\"n\">acme<\/span><span class=\"o\">-<\/span><span class=\"n\">challenge<\/span><span class=\"o\">\/<\/span> <span class=\"err\">{<\/span>\n    <span class=\"n\">default_type<\/span> <span class=\"ss\">&quot;text\/plain&quot;<\/span><span class=\"p\">;<\/span>\n    <span class=\"n\">root<\/span> <span class=\"o\">\/<\/span><span class=\"n\">var<\/span><span class=\"o\">\/<\/span><span class=\"n\">www<\/span><span class=\"o\">\/<\/span><span class=\"n\">letsencrypt<\/span><span class=\"p\">;<\/span>\n<span class=\"err\">}<\/span>\n<\/pre><\/div>\n\n\n<p>Then we can create an empty challenges directory, that's where Let's Ecnrypt will be adding the challenges to later on.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">sudo<\/span> <span class=\"n\">mkdir<\/span> <span class=\"o\">-<\/span><span class=\"n\">p<\/span> <span class=\"o\">\/<\/span><span class=\"n\">var<\/span><span class=\"o\">\/<\/span><span class=\"n\">www<\/span><span class=\"o\">\/<\/span><span class=\"n\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"p\">.<\/span><span class=\"n\">well<\/span><span class=\"o\">-<\/span><span class=\"n\">known<\/span><span class=\"o\">\/<\/span><span class=\"n\">acme<\/span><span class=\"o\">-<\/span><span class=\"n\">challenge<\/span>\n<\/pre><\/div>\n\n\n<p>Now that we have <code>\/etc\/nginx\/snippets\/letsencrypt.conf<\/code> available, we can later plug it into any individual Nginx website configuration and have it serve challenges for that domain on the web server.<\/p>\n<h3>SSL configuration<\/h3>\n<p>In order to run the web server on SSL, we need to provide some configuration related to the SSL certificate such as encryption type, headers, protocols etc...<\/p>\n<p>This configuration can also be added into a separate file, and later on plugged into any Nginx configuration that will use Let's Encrypt certificate.<\/p>\n<p>Lets create the file<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"n\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"n\">ssl<\/span><span class=\"p\">.<\/span><span class=\"n\">conf<\/span>\n<\/pre><\/div>\n\n\n<p>with the following contents<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nt\">ssl_session_timeout<\/span> <span class=\"nt\">1d<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_session_cache<\/span> <span class=\"nt\">shared<\/span><span class=\"p\">:<\/span><span class=\"nd\">SSL<\/span><span class=\"p\">:<\/span><span class=\"nd\">50m<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_session_tickets<\/span> <span class=\"nt\">off<\/span><span class=\"o\">;<\/span>\n\n<span class=\"nt\">ssl_protocols<\/span> <span class=\"nt\">TLSv1<\/span><span class=\"p\">.<\/span><span class=\"nc\">2<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_ciphers<\/span> <span class=\"nt\">EECDH<\/span><span class=\"o\">+<\/span><span class=\"nt\">AESGCM<\/span><span class=\"p\">:<\/span><span class=\"nd\">EECDH<\/span><span class=\"o\">+<\/span><span class=\"nt\">AES<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_ecdh_curve<\/span> <span class=\"nt\">secp384r1<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_prefer_server_ciphers<\/span> <span class=\"nt\">on<\/span><span class=\"o\">;<\/span>\n\n<span class=\"nt\">ssl_stapling<\/span> <span class=\"nt\">on<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">ssl_stapling_verify<\/span> <span class=\"nt\">on<\/span><span class=\"o\">;<\/span>\n\n<span class=\"nt\">add_header<\/span> <span class=\"nt\">Strict-Transport-Security<\/span> <span class=\"s2\">&quot;max-age=15768000; includeSubdomains; preload&quot;<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">add_header<\/span> <span class=\"nt\">X-Frame-Options<\/span> <span class=\"nt\">DENY<\/span><span class=\"o\">;<\/span>\n<span class=\"nt\">add_header<\/span> <span class=\"nt\">X-Content-Type-Options<\/span> <span class=\"nt\">nosniff<\/span><span class=\"o\">;<\/span>\n<\/pre><\/div>\n\n\n<h3>Nginx basic configuration<\/h3>\n<p>Once the above 2 files are ready, we can now include them in any website specific Nginx configuration. <\/p>\n<p>We'll first need set up a basic Nginx config (HTTP only) on our website domain in order to serve the challenges and identify the domain name ownership. We'll later on build up on this same Nginx config file for enabling SSL after obtaining the SSL certificate in step 2.<\/p>\n<p><strong>If you already have an established website being served on HTTP, you probably have a very similar setup to the below. All you will need to do in that case is to just reference <code>include \/etc\/nginx\/snippets\/letsencrypt.conf;<\/code> in your existing config file and restart your web server. Otherwise, you can create a config from scratch as specified below.<\/strong><\/p>\n<p>Create your Nginx config file<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"n\">sites<\/span><span class=\"o\">-<\/span><span class=\"n\">available<\/span><span class=\"o\">\/<\/span><span class=\"n\">mywebsite<\/span><span class=\"p\">.<\/span><span class=\"n\">conf<\/span>\n<\/pre><\/div>\n\n\n<p>With the contents similar to<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nv\">server<\/span> {\n    <span class=\"nv\">listen<\/span> <span class=\"mi\">80<\/span> <span class=\"nv\">default_server<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">listen<\/span> [::]:<span class=\"mi\">80<\/span> <span class=\"nv\">default_server<\/span> <span class=\"nv\">ipv6only<\/span><span class=\"o\">=<\/span><span class=\"nv\">on<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">server_name<\/span> <span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span> <span class=\"nv\">www<\/span>.<span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"k\">include<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"nv\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span>.<span class=\"nv\">conf<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">root<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">var<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span><span class=\"o\">\/<\/span><span class=\"nv\">mywebsite<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">index<\/span> <span class=\"nv\">index<\/span>.<span class=\"nv\">html<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">location<\/span> <span class=\"o\">\/<\/span> {\n        <span class=\"nv\">try_files<\/span> $<span class=\"nv\">uri<\/span> $<span class=\"nv\">uri<\/span><span class=\"o\">\/<\/span> <span class=\"o\">=<\/span><span class=\"mi\">404<\/span><span class=\"c1\">;<\/span>\n    }\n}\n<\/pre><\/div>\n\n\n<p>Enable the config file<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">ln<\/span> <span class=\"o\">-<\/span><span class=\"n\">s<\/span> <span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"n\">sites<\/span><span class=\"o\">-<\/span><span class=\"n\">available<\/span><span class=\"o\">\/<\/span><span class=\"n\">mywebsite<\/span><span class=\"p\">.<\/span><span class=\"n\">conf<\/span> <span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"n\">sites<\/span><span class=\"o\">-<\/span><span class=\"n\">enabled<\/span><span class=\"o\">\/<\/span><span class=\"n\">mywebsite<\/span><span class=\"p\">.<\/span><span class=\"n\">conf<\/span>\n<\/pre><\/div>\n\n\n<p>Restart the web server<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">sudo<\/span> <span class=\"n\">service<\/span> <span class=\"n\">nginx<\/span> <span class=\"k\">restart<\/span>\n<\/pre><\/div>\n\n\n<p>Once this is done, the web server should be able to serve challenges under <code>.well-known\/acme-challenge<\/code> through your domain name. As you have noticed, this is after including <code>letsecrypt.conf<\/code> into our domain's config.<\/p>\n<h2>Step 2: Install and generate a Let's Encrypt certificate<\/h2>\n<p>Now that the challenges can be served under the domain, we'll be able to verify the ownership. Proceed with installing Let's Encrypt and obtaining a certificate.<\/p>\n<p>Install Let's Encrypt via <\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">sudo<\/span> <span class=\"n\">apt<\/span><span class=\"o\">-<\/span><span class=\"k\">get<\/span> <span class=\"n\">install<\/span> <span class=\"n\">letsencrypt<\/span>\n<\/pre><\/div>\n\n\n<p>Obtain the certificate via<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">letsencrypt<\/span><span class=\"w\"> <\/span><span class=\"n\">certonly<\/span><span class=\"w\"> <\/span><span class=\"c1\">--webroot -w \/var\/www\/letsencrypt -d www.mywebsite.com -d mywebsite.com --email your@email.com --agree-tos<\/span>\n<\/pre><\/div>\n\n\n<p>Here is a breakdown explaining the command parameters above:<\/p>\n<ul>\n<li><strong>-w \/var\/www\/letsencrypt<\/strong> Specifies the root directory that we're serving your website challenges from<\/li>\n<li><strong>--webroot<\/strong> Specifies that we're using the web root mode<\/li>\n<li><strong>-d www.mywebsite.com<\/strong> Specifies the domain name we're issuing the certificate for, it can be multiple ones as it's above with www and without www<\/li>\n<li><strong>--email your@email.com<\/strong> Specifies the working email address to to associate with this certificate.<\/li>\n<\/ul>\n<p>After running the command, the SSL related keys and files will be available under<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">\/<\/span><span class=\"n\">etc<\/span><span class=\"o\">\/<\/span><span class=\"n\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"n\">live<\/span><span class=\"o\">\/<\/span><span class=\"n\">www<\/span><span class=\"p\">.<\/span><span class=\"n\">mywebsite<\/span><span class=\"p\">.<\/span><span class=\"n\">com<\/span><span class=\"o\">\/<\/span>\n<\/pre><\/div>\n\n\n<p>For more information about the <code>letsencrypt<\/code> command check out the detailed <a href=\"http:\/\/letsencrypt.readthedocs.io\/en\/latest\/using.html#certbot-commands\">official docs<\/a>.<\/p>\n<h2>Step 3: Integrate the certificate into the config<\/h2>\n<p>Now that the certificate and Nginx domain config are ready, all we have to do is link to the certificate of the domain from the site's config. Open up <code>\/etc\/nginx\/sites-available\/mywebsite.conf<\/code>.<\/p>\n<p>Adding the contents below to the file will enable SSL on the <strong>www<\/strong> version of the domain.<\/p>\n<div class=\"highlight\"><pre><span><\/span> <span class=\"nv\">server<\/span> {\n    <span class=\"nv\">server_name<\/span> <span class=\"nv\">www<\/span>.<span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">listen<\/span> <span class=\"mi\">443<\/span> <span class=\"nv\">ssl<\/span> <span class=\"nv\">http2<\/span> <span class=\"nv\">default_server<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">listen<\/span> [::]:<span class=\"mi\">443<\/span> <span class=\"nv\">ssl<\/span> <span class=\"nv\">http2<\/span> <span class=\"nv\">default_server<\/span> <span class=\"nv\">ipv6only<\/span><span class=\"o\">=<\/span><span class=\"nv\">on<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">ssl_certificate<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">fullchain<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">ssl_certificate_key<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">privkey<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">ssl_trusted_certificate<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">fullchain<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"k\">include<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"nv\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"nv\">ssl<\/span>.<span class=\"nv\">conf<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">root<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">var<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span><span class=\"o\">\/<\/span><span class=\"nv\">mywebsite<\/span>.<span class=\"nv\">com<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">index<\/span> <span class=\"nv\">index<\/span>.<span class=\"nv\">html<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">location<\/span> <span class=\"o\">\/<\/span> {\n        <span class=\"nv\">try_files<\/span> $<span class=\"nv\">uri<\/span> $<span class=\"nv\">uri<\/span><span class=\"o\">\/<\/span> <span class=\"o\">=<\/span><span class=\"mi\">404<\/span><span class=\"c1\">;<\/span>\n    }\n}\n<\/pre><\/div>\n\n\n<p>The above domain configuration is very similar to the initial one, the difference is that<\/p>\n<ul>\n<li>It listens on port 443 (the default port for SSL)<\/li>\n<li>It's for the www version of the domain<\/li>\n<li>It includes the <code>ssl.conf<\/code> file previously created in step 1 and links the generated certificate via <strong>ssl_certificate<\/strong>, <strong>ssl_certificate_key<\/strong>, and <strong>ssl_trusted_certificate<\/strong> properties.<\/li>\n<\/ul>\n<p>Restarting the web server via <code>sudo service nginx restart<\/code> will enable this configuration and allow us to access the website via <strong>https:\/\/www.mywebsite.com<\/strong> hurray! :)<\/p>\n<p>One important thing to notice is that the site is still accessible via non www and non https URls such as<\/p>\n<ul>\n<li>http:\/\/mywebsite.com<\/li>\n<li>http:\/\/www.mywebsite.com<\/li>\n<\/ul>\n<p>And <strong>https:\/\/mywebsite.com<\/strong> is not even accessible.<\/p>\n<p>It's usually a best practice (especially for SEO) to just force https on your domain and use only one style either with www or without www. This can be easily done through 301 redirects on those variations.<\/p>\n<p>First of all update the initially created non https config to redirect all requests to https:\/\/www.mywebsite.com via <\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nv\">server<\/span> {\n    <span class=\"nv\">listen<\/span> <span class=\"mi\">80<\/span> <span class=\"nv\">default_server<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">listen<\/span> [::]:<span class=\"mi\">80<\/span> <span class=\"nv\">default_server<\/span> <span class=\"nv\">ipv6only<\/span><span class=\"o\">=<\/span><span class=\"nv\">on<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">server_name<\/span> <span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span> <span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"k\">include<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"nv\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span>.<span class=\"nv\">conf<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">location<\/span> <span class=\"o\">\/<\/span> {\n        <span class=\"k\">return<\/span> <span class=\"mi\">301<\/span> <span class=\"nv\">https<\/span>:<span class=\"o\">\/\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span>$<span class=\"nv\">request_uri<\/span><span class=\"c1\">;<\/span>\n    }\n}\n<\/pre><\/div>\n\n\n<p>Then also make sure to redirect non www https to www by adding<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nv\">server<\/span> {\n    <span class=\"nv\">listen<\/span> <span class=\"mi\">443<\/span> <span class=\"nv\">ssl<\/span> <span class=\"nv\">http2<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">listen<\/span> [::]:<span class=\"mi\">443<\/span> <span class=\"nv\">ssl<\/span> <span class=\"nv\">http2<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">server_name<\/span> <span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">ssl_certificate<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">fullchain<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">ssl_certificate_key<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">privkey<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"nv\">ssl_trusted_certificate<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">letsencrypt<\/span><span class=\"o\">\/<\/span><span class=\"nv\">live<\/span><span class=\"o\">\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span><span class=\"o\">\/<\/span><span class=\"nv\">fullchain<\/span>.<span class=\"nv\">pem<\/span><span class=\"c1\">;<\/span>\n    <span class=\"k\">include<\/span> <span class=\"o\">\/<\/span><span class=\"nv\">etc<\/span><span class=\"o\">\/<\/span><span class=\"nv\">nginx<\/span><span class=\"o\">\/<\/span><span class=\"nv\">snippets<\/span><span class=\"o\">\/<\/span><span class=\"nv\">ssl<\/span>.<span class=\"nv\">conf<\/span><span class=\"c1\">;<\/span>\n\n    <span class=\"nv\">location<\/span> <span class=\"o\">\/<\/span> {\n        <span class=\"k\">return<\/span> <span class=\"mi\">301<\/span> <span class=\"nv\">https<\/span>:<span class=\"o\">\/\/<\/span><span class=\"nv\">www<\/span>.<span class=\"nv\">mydomain<\/span>.<span class=\"nv\">com<\/span>$<span class=\"nv\">request_uri<\/span><span class=\"c1\">;<\/span>\n    }\n}\n<\/pre><\/div>\n\n\n<p>Once the web server is restarted, we'd have https:\/\/wwww. serving the website by default. Congrats!<\/p>\n<h2>Step 4: Renewing certificates<\/h2>\n<p>A Let\u2019s Encrypt certificates is valid for 90 days after being issues, so it needs to be renewed often. The renewal process is pretty simple, all we have to do is run<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">letsencrypt<\/span> <span class=\"n\">renew<\/span> <span class=\"c1\">--pre-hook &quot;service nginx stop&quot; --post-hook &quot;service nginx start&quot;<\/span>\n<\/pre><\/div>\n\n\n<p>This command will renew certificates expiring in less than 30 days. Notice the pre-hook and post-hook, those are the commands we want to be running before and after renewal, which in this case is stopping and restarting Nginx.<\/p>\n<p>For more details on renewing certificates command check out the docs <a href=\"http:\/\/letsencrypt.readthedocs.io\/en\/latest\/using.html#renewing-certificates\">here<\/a><\/p>\n<p>It would definitely be annoying to login to the server constantly to update the certificates. One thing we can do is add a cronjob to do it for us, open up the crontab file<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"n\">crontab<\/span> <span class=\"o\">-<\/span><span class=\"n\">e<\/span>\n<\/pre><\/div>\n\n\n<p>and include the following line<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"mi\">0<\/span> <span class=\"mi\">0<\/span> <span class=\"mi\">1<\/span> <span class=\"o\">*<\/span> <span class=\"o\">*<\/span> <span class=\"n\">letsencrypt<\/span> <span class=\"n\">renew<\/span> <span class=\"c1\">--pre-hook &quot;service nginx stop&quot; --post-hook &quot;service nginx start &gt;&gt; \/var\/log\/letsencrypt.log<\/span>\n<\/pre><\/div>\n\n\n<p>This sets the renewal command to run on the first of every month at 12:00AM, updating any certificates that are expiring in less than 30 days.<\/p>\n<p>After this step, your website should be all set and running on Let's Encrypt.<\/p>\n<p>Delivering more secure web products is crucial for your users. End users are already demanding the availability of secure web pages. As a matter of fact, Google Chrome is going to eventually <a href=\"https:\/\/security.googleblog.com\/2016\/09\/moving-towards-more-secure-web.html\">label all HTTP pages as non-secure<\/a> in very obvious ways for users. <\/p>\n<p>So what are you waiting for? Let's Encrypt!<\/p>","category":[{"@attributes":{"term":"SSL"}},{"@attributes":{"term":"free"}},{"@attributes":{"term":"ubuntu"}},{"@attributes":{"term":"nginx"}},{"@attributes":{"term":"letsencrypt"}},{"@attributes":{"term":"encrypt"}},{"@attributes":{"term":"https"}},{"@attributes":{"term":"security"}}]},{"title":"Bootstrap your vanilla JS game with this project setup and gulp build","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/bootstrap-vanilla-js-game-gulp-build-project-setup\/","rel":"alternate"}},"published":"2016-08-14T06:00:00+03:00","updated":"2016-08-14T06:00:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2016-08-14:\/web-development\/bootstrap-vanilla-js-game-gulp-build-project-setup\/","summary":"<p>Building your own vanilla HTML5 game without dependencies might sound like a tough and odd job to do. In fact, it's a really fun experience and a huge opportunity to sharpen your JS and general programming skills. One awesome competition that empowers this movement is the JS13K competition. It ...<\/p>","content":"<p>Building your own vanilla HTML5 game without dependencies might sound like a tough and odd job to do. In fact, it's a really fun experience and a huge opportunity to sharpen your JS and general programming skills.<\/p>\n<p>One awesome competition that empowers this movement is the <a href=\"http:\/\/2016.js13kgames.com\/\">JS13K<\/a> competition. It's a 1 month competition where you build an HTML5 game with a 13kb file size limit. While this post is dedicated to this competition, the content applies to building small JS games in general.<\/p>\n<p>As a warm up for the competition, I've decided to prepare a project setup and gulp build, which can be found <a href=\"https:\/\/github.com\/aymanfarhat\/js13k-starter\">here<\/a> with all the setup instructions.<\/p>\n<p>This post will be explaining the project setup, where each piece falls and describe the gulp build process, in the bootstrap project linked above. Assuming you already have some experience with HTML5 games and basic concepts like the game loop.<\/p>\n<h2>Project structure<\/h2>\n<div class=\"highlight\"><pre><span><\/span><span class=\"p\">.<\/span>\n<span class=\"o\">+<\/span><span class=\"c1\">-- README.md<\/span>\n<span class=\"o\">+<\/span><span class=\"c1\">-- _build<\/span>\n<span class=\"o\">?<\/span>   <span class=\"o\">+<\/span><span class=\"c1\">-- game.min..css<\/span>\n<span class=\"o\">?<\/span>   <span class=\"o\">+<\/span><span class=\"c1\">-- game.min.js<\/span>\n<span class=\"o\">?<\/span>   <span class=\"err\">\\<\/span><span class=\"c1\">-- index.html<\/span>\n<span class=\"o\">+<\/span><span class=\"c1\">-- _dist<\/span>\n<span class=\"o\">?<\/span>   <span class=\"err\">\\<\/span><span class=\"c1\">-- game.zip<\/span>\n<span class=\"o\">+<\/span><span class=\"c1\">-- gulpfile.js<\/span>\n<span class=\"o\">+<\/span><span class=\"c1\">-- package.json<\/span>\n<span class=\"err\">\\<\/span><span class=\"c1\">-- src<\/span>\n    <span class=\"o\">+<\/span><span class=\"c1\">-- css<\/span>\n    <span class=\"o\">?<\/span>   <span class=\"err\">\\<\/span><span class=\"c1\">-- style.css<\/span>\n    <span class=\"o\">+<\/span><span class=\"c1\">-- images<\/span>\n    <span class=\"o\">+<\/span><span class=\"c1\">-- index.html<\/span>\n    <span class=\"err\">\\<\/span><span class=\"c1\">-- js<\/span>\n        <span class=\"o\">+<\/span><span class=\"c1\">-- draw.js<\/span>\n        <span class=\"o\">+<\/span><span class=\"c1\">-- game.js<\/span>\n        <span class=\"o\">+<\/span><span class=\"c1\">-- random_obj.js<\/span>\n        <span class=\"err\">\\<\/span><span class=\"c1\">-- util.js<\/span>\n<\/pre><\/div>\n\n\n<h3>At the root<\/h3>\n<p>Here, we have our gulp build file, our npm dependencies in <strong>package.json<\/strong> and two directories <code>_build<\/code> and <code>_dist<\/code>. The job of the gulp build process is to output the final concatenated, minified js, css and html code into _build, and then zip all of the contents and store them under the _dist directory.<\/p>\n<p>This process runs automatically every time the work is saved, which helps keep an eye on the final output especially on the size of the zip file that is being updated in the _dist directory, before finally submitting.<\/p>\n<h3>The source code<\/h3>\n<p>Everything related to the source of the project would go under <code>src<\/code> which would contain our css, images, and js code each in its respective directory.<\/p>\n<h3>Entry point<\/h3>\n<p>Also notice that <code>index.html<\/code> is at the root of the src folder, which is the entry point to our game, in it we'd initialise the canvas and include all dependencies. This would be the non-compiled version which would run on the local dev server and looks something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"cp\">&lt;!DOCTYPE HTML&gt;<\/span>\n<span class=\"p\">&lt;<\/span><span class=\"nt\">html<\/span> <span class=\"na\">lang<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;en&quot;<\/span><span class=\"p\">&gt;<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">head<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">title<\/span><span class=\"p\">&gt;<\/span>JS13K Starter<span class=\"p\">&lt;\/<\/span><span class=\"nt\">title<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">meta<\/span> <span class=\"na\">charset<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;UTF-8&quot;<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">meta<\/span> <span class=\"na\">name<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;viewport&quot;<\/span> <span class=\"na\">content<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1, user-scalable=0&quot;<\/span> <span class=\"p\">\/&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">meta<\/span> <span class=\"na\">name<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;apple-mobile-web-app-capable&quot;<\/span> <span class=\"na\">content<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;yes&quot;<\/span> <span class=\"p\">\/&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">meta<\/span> <span class=\"na\">name<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;apple-mobile-web-app-status-bar-style&quot;<\/span> <span class=\"na\">content<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;black-translucent&quot;<\/span> <span class=\"p\">\/&gt;<\/span>\n        <span class=\"c\">&lt;!-- build:css --&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">link<\/span> <span class=\"na\">rel<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;stylesheet&quot;<\/span> <span class=\"na\">type<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;text\/css&quot;<\/span> <span class=\"na\">href<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;.\/css\/style.css&quot;<\/span> <span class=\"p\">\/&gt;<\/span>\n        <span class=\"c\">&lt;!-- endbuild --&gt;<\/span>\n    <span class=\"p\">&lt;\/<\/span><span class=\"nt\">head<\/span><span class=\"p\">&gt;<\/span>\n    <span class=\"p\">&lt;<\/span><span class=\"nt\">body<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">h1<\/span><span class=\"p\">&gt;<\/span>JS13K Starter Project<span class=\"p\">&lt;\/<\/span><span class=\"nt\">h1<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">h3<\/span><span class=\"p\">&gt;<\/span>Click to randomize!<span class=\"p\">&lt;\/<\/span><span class=\"nt\">h3<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">canvas<\/span><span class=\"p\">&gt;&lt;\/<\/span><span class=\"nt\">canvas<\/span><span class=\"p\">&gt;<\/span>\n\n        <span class=\"c\">&lt;!-- build:js --&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">script<\/span> <span class=\"na\">src<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;.\/js\/game.js&quot;<\/span><span class=\"p\">&gt;&lt;\/<\/span><span class=\"nt\">script<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">script<\/span> <span class=\"na\">src<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;.\/js\/draw.js&quot;<\/span><span class=\"p\">&gt;&lt;\/<\/span><span class=\"nt\">script<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">script<\/span> <span class=\"na\">src<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;.\/js\/util.js&quot;<\/span><span class=\"p\">&gt;&lt;\/<\/span><span class=\"nt\">script<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"p\">&lt;<\/span><span class=\"nt\">script<\/span> <span class=\"na\">src<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;.\/js\/random_obj.js&quot;<\/span><span class=\"p\">&gt;&lt;\/<\/span><span class=\"nt\">script<\/span><span class=\"p\">&gt;<\/span>\n        <span class=\"c\">&lt;!-- endbuild --&gt;<\/span>\n    <span class=\"p\">&lt;\/<\/span><span class=\"nt\">body<\/span><span class=\"p\">&gt;<\/span>\n<span class=\"p\">&lt;\/<\/span><span class=\"nt\">html<\/span><span class=\"p\">&gt;<\/span>\n<\/pre><\/div>\n\n\n<h3>JS Code<\/h3>\n<p>As for the JS, one easy way to structure is it follow a couple of simple principles:<\/p>\n<p>Wrap your game code around a namespace\nSeparate code into different files based on their functionality\nA simple way to namespace your game is to have a global object for the game, I named it $ in this case as its short and jQuery is not being used in the project. Under that name space I'd attach different objects and functions, used across different files.<\/p>\n<p>For example, we can have reusable functions around drawing on canvas available under the <code>$.Draw<\/code> module inside the draw.js file which contains stuff like <code>$.Draw.rect<\/code>, <code>$.Draw.circle<\/code> or anything related to drawing on the screen.<\/p>\n<p>As for the logic of different characters or entities related to the game such as a meteor, hero, or a villain, those would have their own files and manage their own logic relative to the game and its loop. Those modules would have a class like structure with a constructor. That's because we want to be creating several instances of our game objects into the game such as several meteors, one ups, etc...<\/p>\n<p>The code for such a module would look something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"s2\">&quot;use strict&quot;<\/span><span class=\"p\">;<\/span>\n\n<span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">RandomObj<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">x<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">util<\/span><span class=\"p\">.<\/span><span class=\"nx\">randomInRange<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">width<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">y<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">util<\/span><span class=\"p\">.<\/span><span class=\"nx\">randomInRange<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">height<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">dimension<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">targetDimension<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">util<\/span><span class=\"p\">.<\/span><span class=\"nx\">randomInRange<\/span><span class=\"p\">(<\/span><span class=\"mi\">50<\/span><span class=\"p\">,<\/span> <span class=\"mi\">70<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">growthSpeed<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">util<\/span><span class=\"p\">.<\/span><span class=\"nx\">randomInRange<\/span><span class=\"p\">(<\/span><span class=\"mf\">0.5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">color<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">util<\/span><span class=\"p\">.<\/span><span class=\"nx\">pickRandomFromObject<\/span><span class=\"p\">(<\/span><span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">colors<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">RandomObj<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">render<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">Draw<\/span><span class=\"p\">.<\/span><span class=\"nx\">rect<\/span><span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">x<\/span><span class=\"p\">,<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">y<\/span><span class=\"p\">,<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">dimension<\/span><span class=\"p\">,<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">dimension<\/span><span class=\"p\">,<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">color<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">RandomObj<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">update<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">dimension<\/span> <span class=\"o\">&lt;<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">targetDimension<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">dimension<\/span> <span class=\"o\">+=<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">growthSpeed<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>Creating an instance of our RandomObj would be something like <\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">var<\/span> <span class=\"nx\">randomObjectInstance<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">RandomObj<\/span><span class=\"p\">();<\/span>\n<\/pre><\/div>\n\n\n<p>which ideally would be instantiated from within our game loop. Each game object class would implement two essential functions, <strong>render<\/strong> and <strong>update<\/strong>.<\/p>\n<p>Each of those functions would be called automatically by our game loop on each iteration.<\/p>\n<p>Calling <code>randomObjectInstance.render()<\/code> would trigger the painting code for that specific instance of that specific game object.<\/p>\n<p>Calling <code>randomObjectInstance.update()<\/code> would trigger the change to be done on that instance's state such as growing in size + 1 when that game loop tick takes place.<\/p>\n<p>The game loop itself would be as simple as an infinite loop that triggers a render and update calls on each iteration on all the game objects available in the world. Example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">loop<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">render<\/span><span class=\"p\">();<\/span>\n    <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">update<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"nb\">window<\/span><span class=\"p\">.<\/span><span class=\"nx\">requestAnimFrame<\/span><span class=\"p\">(<\/span><span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">loop<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">update<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">entities<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span><span class=\"o\">++<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">entities<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">].<\/span><span class=\"nx\">update<\/span><span class=\"p\">();<\/span>    \n    <span class=\"p\">}<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">render<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">Draw<\/span><span class=\"p\">.<\/span><span class=\"nx\">clear<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">entities<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span><span class=\"o\">++<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">entities<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">].<\/span><span class=\"nx\">render<\/span><span class=\"p\">();<\/span>    \n    <span class=\"p\">}<\/span>\n<span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>The game loop is available in the <a href=\"https:\/\/github.com\/aymanfarhat\/js13k-starter\/blob\/master\/src\/js\/game.js\">game.js<\/a> file in the project.<\/p>\n<h2>Gulp build<\/h2>\n<p>The <a href=\"https:\/\/github.com\/aymanfarhat\/js13k-starter\/blob\/master\/gulpfile.js\">build script<\/a> is pretty straightforward, as mentioned earlier, its all about concatenating, minifying the source then outputting a final zip file. They're all divided to separate tasks <strong>serve<\/strong>, <strong>buildCSS<\/strong>, <strong>buildJS<\/strong>, <strong>buildIndex<\/strong>, and <strong>zipBuild<\/strong>. And finally, they're all grouped into one main <strong>build<\/strong> command which runs them in order.<\/p>\n<p>This runs every time changes are saved on the project thanks to the <strong>watch<\/strong> command. In addition, the game's entry point index.html via a serve command.<\/p>\n<p>To get everything up and running in one shot, just run gulp this will run an initial build, serve the app on the localhost and will run the watch command which will check for any changes and trigger a new build and zip.<\/p>\n<p>After each save, the gulp build will output the current size of the zipped project in order to stay alert on the size of the project. Something like <\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"p\">[<\/span><span class=\"mi\">09<\/span><span class=\"p\">:<\/span><span class=\"mi\">32<\/span><span class=\"p\">:<\/span><span class=\"mi\">55<\/span><span class=\"p\">]<\/span> <span class=\"k\">Size<\/span> <span class=\"k\">of<\/span> <span class=\"n\">game<\/span><span class=\"p\">.<\/span><span class=\"n\">zip<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">.<\/span><span class=\"mi\">75<\/span> <span class=\"n\">KB<\/span>\n<\/pre><\/div>\n\n\n<p>You can find the starter project example on <a href=\"https:\/\/github.com\/aymanfarhat\/js13k-starter\">this link<\/a>.<\/p>\n<p>I hope you find this JS13K starter useful and I'm looking forward to participating and seeing all the awesome submissions this year. Would love to hear your feedback and suggestions on this post.<\/p>","category":[{"@attributes":{"term":"gulp"}},{"@attributes":{"term":"canvas"}},{"@attributes":{"term":"project"}},{"@attributes":{"term":"build"}},{"@attributes":{"term":"js13k"}},{"@attributes":{"term":"structure"}},{"@attributes":{"term":"html5"}}]},{"title":"Common pitfalls when working with Javascript Arrays","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/common-pitfalls-when-working-with-javascript-arrays\/","rel":"alternate"}},"published":"2014-03-27T15:00:00+02:00","updated":"2014-03-27T15:00:00+02:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2014-03-27:\/web-development\/common-pitfalls-when-working-with-javascript-arrays\/","summary":"<p>In most programming languages, an array is a data structure represented by an arrangement of items at equally spaced addresses in computer memory. Unfortunately, that is not the case with Javascript. A Javascript array is simply an object with array like characteristics reflected through certain methods. Apart from being much \u2026<\/p>","content":"<p>In most programming languages, an array is a data structure represented by an arrangement of items at equally spaced addresses in computer memory. Unfortunately, that is not the case with Javascript. A Javascript array is simply an object with array like characteristics reflected through certain methods. Apart from being much ...<\/p>\n<p>In most programming languages, an array is a data structure represented by an arrangement of items at equally spaced addresses in computer memory. Unfortunately, that is not the case with Javascript. A Javascript array is simply an object with array like characteristics reflected through certain methods.<\/p>\n<p>Apart from being much slower than regular arrays, they can be quite problematic when misused. I will be summarizing some of the pitfalls that I have come across, along with tips to avoid them.<\/p>\n<h2>Length<\/h2>\n<p>The length of an array is computed as the largest integer property in the object plus one, and that is not necessarily the number of objects in the array! Lets take a simple example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">var<\/span> <span class=\"nx\">myArray<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">myArray<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ outputs 0<\/span>\n<span class=\"nx\">myArray<\/span><span class=\"p\">[<\/span><span class=\"mi\">100<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;some value&#39;<\/span><span class=\"p\">;<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">myArray<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ outputs 101 despite containing one element<\/span>\n<\/pre><\/div>\n\n\n<p>That is why it is advised to use <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/push\">Array.prototype.push<\/a> for all insertions and refrain from explicitly setting index values. The push method will insert the value with the right key\/index.<\/p>\n<h2>Removing elements<\/h2>\n<p>The <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/delete\">delete operator<\/a> can be used to remove a property from any object. Arrays are objects so if we apply that we'll end up with a hole in the array as the indexes(keys) will not shift automatically to reflect that change. Example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">var<\/span> <span class=\"nx\">myArray<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">];<\/span>\n<span class=\"k\">delete<\/span> <span class=\"nx\">myArray<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">];<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">myArray<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]);<\/span> <span class=\"c1\">\/\/ outputs undefined while the expected value was c<\/span>\n<\/pre><\/div>\n\n\n<p>Bottom line, using <strong>delete<\/strong> on arrays should be avoided.<\/p>\n<p>The proper method for removing an element on a certain index would be <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/splice\">Array.prototype.splice<\/a> Other safe methods worth mentioning: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/pop\">Array.prototype.pop<\/a> - add\/remove elements from the end of the array <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/shift\">Array.prototype.shift<\/a> - add\/remove elements from the beginning of the array<\/p>\n<h2>Sorting<\/h2>\n<p><a href=\"https:\/\/developer.mozilla.org\/en\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/sort\">Array.prototype.sort()<\/a> is the go to method for sorting arrays, but there are a couple of issues we need to be aware of.<\/p>\n<p>The sorting order is by default <a href=\"http:\/\/en.wikipedia.org\/wiki\/Lexicographical_order\">lexicographic<\/a> and not numeric regardless of the types of values in the array. Even if the array is all numbers, all values will be converted to string and sorted lexicographically. Here is an example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">var<\/span> <span class=\"nx\">myarray<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">80<\/span><span class=\"p\">,<\/span> <span class=\"mi\">9<\/span><span class=\"p\">,<\/span> <span class=\"mi\">34<\/span><span class=\"p\">,<\/span> <span class=\"mi\">23<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">];<\/span>\n<span class=\"nx\">myarray<\/span><span class=\"p\">.<\/span><span class=\"nx\">sort<\/span><span class=\"p\">();<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">myarray<\/span><span class=\"p\">);<\/span> <span class=\"c1\">\/\/ outputs: [1, 23, 34, 5, 80, 9] <\/span>\n<\/pre><\/div>\n\n\n<p>While the correct output for the above should be <code>[ 1, 5, 9, 23, 34, 80 ]<\/code><\/p>\n<p>Fortunately, the sort method takes an optional compare function in order to specify the sort order. When the compare function is supplied no type will take place. The order depends on the return value of the compare function. To learn more about the rules I suggest checking out the <a href=\"https:\/\/developer.mozilla.org\/en\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/sort#Description\">description of compareFunction on MDN<\/a><\/p>\n<p>Back to our last example, the proper way to sort an array of numbers would be:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">myarray<\/span><span class=\"p\">.<\/span><span class=\"nx\">sort<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">a<\/span><span class=\"p\">,<\/span> <span class=\"nx\">b<\/span><span class=\"p\">){<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">a<\/span> <span class=\"o\">&lt;<\/span> <span class=\"nx\">b<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">a<\/span> <span class=\"o\">&gt;<\/span> <span class=\"nx\">b<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">else<\/span>\n        <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">});<\/span>\n<\/pre><\/div>\n\n\n<h2>Type Checking<\/h2>\n<p>Javascript's <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Operators\/typeof\">typeof operator<\/a> does not distinguish between an array and any other object.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"k\">typeof<\/span> <span class=\"p\">[]);<\/span> <span class=\"c1\">\/\/ outputs: object<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"k\">typeof<\/span> <span class=\"p\">{});<\/span> <span class=\"c1\">\/\/ outputs: object<\/span>\n<\/pre><\/div>\n\n\n<p>In order to identify an array type there are a couple of ways. One thing we can do is check <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/constructor\">Object.prototype.constructor<\/a> method which returns a reference to the object function that created the instance's prototype.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">check_array<\/span> <span class=\"p\">(<\/span><span class=\"nx\">value<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nx\">value<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"k\">typeof<\/span> <span class=\"nx\">value<\/span> <span class=\"o\">===<\/span> <span class=\"s1\">&#39;object&#39;<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">value<\/span><span class=\"p\">.<\/span><span class=\"nx\">constructor<\/span> <span class=\"o\">===<\/span> <span class=\"nb\">Array<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">check_array<\/span><span class=\"p\">([]));<\/span> <span class=\"c1\">\/\/ outputs: true<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">check_array<\/span><span class=\"p\">({}));<\/span> <span class=\"c1\">\/\/ outputs: false<\/span>\n<\/pre><\/div>\n\n\n<p>Another would be through applying <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/toString\">Object.prototype.toString method<\/a> to get the class.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">check_array<\/span> <span class=\"p\">(<\/span><span class=\"nx\">value<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">Object<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">toString<\/span><span class=\"p\">.<\/span><span class=\"nx\">apply<\/span><span class=\"p\">(<\/span><span class=\"nx\">value<\/span><span class=\"p\">)<\/span> <span class=\"o\">===<\/span> <span class=\"s1\">&#39;[object Array]&#39;<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">check_array<\/span><span class=\"p\">([]));<\/span> <span class=\"c1\">\/\/ outputs: true<\/span>\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">check_array<\/span><span class=\"p\">({}));<\/span> <span class=\"c1\">\/\/ outputs: false<\/span>\n<\/pre><\/div>\n\n\n<h2>for-in loops<\/h2>\n<p>The <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/for...in\">for-in loop<\/a> seems convenient at times but it is meant to iterate over an object properties rather than an array structure. There are two main reasons for that:<\/p>\n<h3>It does not guarantee order<\/h3>\n<p>The use of for-in makes no guarantee over the order of the properties. The order of enumeration depends on the implementation which might differ between browsers. According to this <a href=\"http:\/\/ejohn.org\/blog\/javascript-in-chrome\/\">article<\/a>, all modern implementations iterate through object properties in the order in which they were defined.<\/p>\n<h3>Unexpected properties from the prototype chain<\/h3>\n<p>for-in does not only iterate over properties attached to the object itself but also over its prototypes, and that might result in extra unexpected results. Here is an example<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"c1\">\/\/ Somewhere else in our program we decided to add an extra property for all arrays<\/span>\n<span class=\"nb\">Array<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">foo<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;bar&quot;<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">var<\/span> <span class=\"nx\">myArray<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span><span class=\"mi\">3<\/span><span class=\"p\">];<\/span>\n<span class=\"kd\">var<\/span> <span class=\"nx\">result<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n\n<span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"nx\">key<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">myArray<\/span><span class=\"p\">){<\/span>\n    <span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nx\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">key<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ Outputs:<\/span>\n<span class=\"c1\">\/\/ 0<\/span>\n<span class=\"c1\">\/\/ 1<\/span>\n<span class=\"c1\">\/\/ 2<\/span>\n<span class=\"c1\">\/\/ foo<\/span>\n<\/pre><\/div>\n\n\n<p>In the above example, <strong>foo<\/strong> becomes part of every array and will show up in a for-in. This can be avoided by checking that property does not belong to the prototype of the object on each iteration via <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/hasOwnProperty\">hasOwnProperty<\/a>, but is all that worth it?<\/p>\n<p>And thats why it is advised to stick with the conventional for statement in order to avoid those problems. As long as the indexes of the array are correct it should work fine.<\/p>\n<h2>The associative array confusion<\/h2>\n<p>Associative arrays similar to those existing in other languages such as PHP do not exist in Javascript. An example such as this would \"work\" but is not correct:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">var<\/span> <span class=\"nx\">myAssocArray<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n<span class=\"nx\">myAssocArray<\/span><span class=\"p\">[<\/span><span class=\"s2\">&quot;foo&quot;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;bar&quot;<\/span><span class=\"p\">;<\/span>\n<\/pre><\/div>\n\n\n<p>The above example is not an associative array but rather an abused array object. The above code works simply because arrays are objects too. As a matter of fact the same thing can be applied to any other object in Javascript. <code>myAssocArray[\"foo\"] = \"bar\"<\/code> is equivalent to <code>myAssocArray.foo = \"bar\"<\/code>, simply adding a new property to the current array object.<\/p>\n<p>For a key\/value pairs structure using vanilla Javascript objects is the right option.<\/p>\n<h2>Did I miss anything?<\/h2>\n<p>I hope you enjoyed this post and found it useful in one way or another. If you think I missed anything, please let me know in the comments. Have a good day!<\/p>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"arrays"}},{"@attributes":{"term":"tips"}},{"@attributes":{"term":"pitfall"}}]},{"title":"An alternative to Javascript's evil setInterval","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/alternative-to-javascript-evil-setinterval\/","rel":"alternate"}},"published":"2013-11-03T12:00:00+02:00","updated":"2013-11-03T12:00:00+02:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-11-03:\/web-development\/alternative-to-javascript-evil-setinterval\/","summary":"<p>If you use Javascript often you might have come across the need for delaying the execution of code within intervals of time with repetition. This is were the native setInterval function comes to use. Despite being useful in many applications, setInterval's shortcomings could blow up your application in some ...<\/p>","content":"<p>If you use Javascript often you might have come across the need for delaying the execution of code within intervals of time with repetition. This is were the native setInterval function comes to use. Despite being useful in many applications, setInterval's shortcomings could blow up your application in some circumstances.<\/p>\n<h2>Why is setInterval evil?<\/h2>\n<h3>Doesn't care whether the callback is still running or not<\/h3>\n<p>In some cases, the function might need longer than the interval time to finish execution. Consider using setInterval to poll a remote server every 5 seconds, network latency, unresponsive server and other variables might prevent the request from completing on time. What would happen is that you'll end up with a bunch of queued requests that may not necessarily return in order.<\/p>\n<h3>Ignores errors<\/h3>\n<p>If for some reason, an error occurs in part of the code that is called by setInterval, it wouldn't break and keeps executing the faulty code.<\/p>\n<h3>Isn't that flexible<\/h3>\n<p>On top of the previously mentioned shortcomings, I'd really appreciate if setInterval had an optional parameter for setting the number of repetitions instead of repeating infinitely.<\/p>\n<h2>A better implementation<\/h2>\n<p>So I implemented my own setInterval function which tackles the above mentioned shortcomings. It supports the expected setInterval parameters with an extra optional one for specifying the number of repetitions to be done.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">interval<\/span><span class=\"p\">(<\/span><span class=\"nx\">func<\/span><span class=\"p\">,<\/span> <span class=\"nx\">wait<\/span><span class=\"p\">,<\/span> <span class=\"nx\">times<\/span><span class=\"p\">){<\/span>\n    <span class=\"kd\">var<\/span> <span class=\"nx\">interv<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">w<\/span><span class=\"p\">,<\/span> <span class=\"nx\">t<\/span><span class=\"p\">){<\/span>\n        <span class=\"k\">return<\/span> <span class=\"kd\">function<\/span><span class=\"p\">(){<\/span>\n            <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"k\">typeof<\/span> <span class=\"nx\">t<\/span> <span class=\"o\">===<\/span> <span class=\"s2\">&quot;undefined&quot;<\/span> <span class=\"o\">||<\/span> <span class=\"nx\">t<\/span><span class=\"o\">--<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">){<\/span>\n                <span class=\"nx\">setTimeout<\/span><span class=\"p\">(<\/span><span class=\"nx\">interv<\/span><span class=\"p\">,<\/span> <span class=\"nx\">w<\/span><span class=\"p\">);<\/span>\n                <span class=\"k\">try<\/span><span class=\"p\">{<\/span>\n                    <span class=\"nx\">func<\/span><span class=\"p\">.<\/span><span class=\"nx\">call<\/span><span class=\"p\">(<\/span><span class=\"kc\">null<\/span><span class=\"p\">);<\/span>\n                <span class=\"p\">}<\/span>\n                <span class=\"k\">catch<\/span><span class=\"p\">(<\/span><span class=\"nx\">e<\/span><span class=\"p\">){<\/span>\n                    <span class=\"nx\">t<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n                    <span class=\"k\">throw<\/span> <span class=\"nx\">e<\/span><span class=\"p\">.<\/span><span class=\"nx\">toString<\/span><span class=\"p\">();<\/span>\n                <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">};<\/span>\n    <span class=\"p\">}(<\/span><span class=\"nx\">wait<\/span><span class=\"p\">,<\/span> <span class=\"nx\">times<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"nx\">setTimeout<\/span><span class=\"p\">(<\/span><span class=\"nx\">interv<\/span><span class=\"p\">,<\/span> <span class=\"nx\">wait<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>The interval function has an internal function called interv which gets invoked automatically via setTimeout, within <strong>interv<\/strong> is a <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Guide\/Closures\">closure<\/a> that checks the the repetition times, invokes the callback and invokes interv again via setTimeout. In case an exception bubbles up from the callback call the interval calling will stop and the exception will be thrown.<\/p>\n<p>This pattern does not guarantee execution on a fixed interval of course, yet it does guarantee that the previous interval has completed before recursing, which I think is much more important.<\/p>\n<h2>Usage<\/h2>\n<p>So to execute a piece of code 5 times with an interval or 10 seconds between each you would do something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nx\">interval<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span><span class=\"p\">(){<\/span>\n        <span class=\"c1\">\/\/ Code block goes here<\/span>\n    <span class=\"p\">},<\/span> <span class=\"mi\">1000<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"p\">);<\/span>\n<\/pre><\/div>\n\n\n<p>Hope you find this snippet useful, feel free to leave your comments below.<\/p>\n<h2>References<\/h2>\n<ul>\n<li><a href=\"http:\/\/ejohn.org\/blog\/how-javascript-timers-work\/\">How Javascript Timers Work<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/window.setInterval\">window.setInterval<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/window.setTimeout\">window.setTimeout<\/a><\/li>\n<\/ul>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"improvement"}},{"@attributes":{"term":"setinterval"}},{"@attributes":{"term":"settimeout"}}]},{"title":"Proxypy: Cross Domain Javascript Requests with Python","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/proxypy-cross-domain-javascript-requests-python\/","rel":"alternate"}},"published":"2013-06-08T17:00:00+03:00","updated":"2013-06-08T17:00:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-06-08:\/web-development\/proxypy-cross-domain-javascript-requests-python\/","summary":"<p>When working with web applications you might run into the need to fetch remote content via Ajax where that content isn't necessarily JSON, such as HTML or config file, or even request JSON content from a remote server that doesn't support JSONP. This is when setting up a ...<\/p>","content":"<p>When working with web applications you might run into the need to fetch remote content via Ajax where that content isn't necessarily JSON, such as HTML or config file, or even request JSON content from a remote server that doesn't support JSONP. This is when setting up a proxy service can be a good idea.<\/p>\n<p>A proxy can act as an intermediary between your Javascript and the remote data, eliminating all the cross domain limitations imposed on the client. The pattern in principle is simple:<\/p>\n<ol>\n<li>Assign to your web application's server some view to receive a request with a parameter of the desired remote content address.<\/li>\n<li>Let the server fetch the content from the remote server via an HTTP request.<\/li>\n<li>Wrap the results into a JSON object and return them back.<\/li>\n<\/ol>\n<p>I was working with Python so I wrote a simple proxy module that can work with any Python web application framework. You can check out the <a href=\"https:\/\/github.com\/aymanfarhat\/proxypy\/blob\/master\/proxypy.py\">source of the module<\/a> on <a href=\"https:\/\/github.com\/aymanfarhat\/proxypy\">Github<\/a> along with an example of a <a href=\"https:\/\/github.com\/aymanfarhat\/proxypy\/tree\/master\/example\">Flask application<\/a> using it.<\/p>\n<p>Include the Proxypy module in your project and import it then assign a view to receive the request and call <code>proxypy.<\/code>get<code>(query_string)<\/code> the method takes a single argument that is the query string received in the request. The query string would work on the following parameters:<\/p>\n<ul>\n<li><strong>url<\/strong> which is the address of the page with the target content to fetch.<\/li>\n<li><strong>headers<\/strong>(optional) if you wish to return the reply headers of the request.<\/li>\n<li><strong>callback<\/strong>(optional) if your request against the proxy service itself is from a different domain.<\/li>\n<\/ul>\n<p>Here is a simple demonstration of usage with <a href=\"http:\/\/flask.pocoo.org\/\">Flask<\/a>, the \"crossdomain\" view receives the request and calls proxypy's get method to fetch the remote content based on the supplied parameters and then returns the JSON string containing the wrapped reply from the remote.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">from<\/span> <span class=\"nn\">flask<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Flask<\/span><span class=\"p\">,<\/span> <span class=\"n\">request<\/span><span class=\"p\">,<\/span> <span class=\"n\">Response<\/span><span class=\"p\">,<\/span> <span class=\"n\">render_template<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">json<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">proxypy<\/span>\n\n<span class=\"n\">app<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Flask<\/span><span class=\"p\">(<\/span><span class=\"vm\">__name__<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@app.route<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;\/&quot;<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">index<\/span><span class=\"p\">():<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">render_template<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;index.html&quot;<\/span><span class=\"p\">)<\/span>\n\n<span class=\"nd\">@app.route<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;\/crossdomain&quot;<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">def<\/span> <span class=\"nf\">crossdom<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">reply<\/span> <span class=\"o\">=<\/span> <span class=\"n\">proxypy<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">request<\/span><span class=\"o\">.<\/span><span class=\"n\">query_string<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">Response<\/span><span class=\"p\">(<\/span><span class=\"n\">reply<\/span><span class=\"p\">,<\/span><span class=\"n\">status<\/span><span class=\"o\">=<\/span><span class=\"mi\">200<\/span><span class=\"p\">,<\/span><span class=\"n\">mimetype<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;application\/json&#39;<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">if<\/span> <span class=\"vm\">__name__<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;__main__&quot;<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">app<\/span><span class=\"o\">.<\/span><span class=\"n\">run<\/span><span class=\"p\">(<\/span><span class=\"n\">debug<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n<\/pre><\/div>\n\n\n<p>You can view a full example in action <a href=\"http:\/\/proxypy.herokuapp.com\/\">here<\/a> and check the full source of the script on <a href=\"https:\/\/github.com\/aymanfarhat\/proxypy\">Github<\/a>.<\/p>\n<p>You might have noticed a couple of limitations in terms of features in this proxy namely, no support for HTTP methods other than GET and this is because I haven't really came across a need for that plus allowing more methods such as POST may increase the possibilities of exploitation.<\/p>\n<p>I hope that you find this module useful in one way or another, would love to see your feedback about this topic in the comments. Have a nice weekend!<\/p>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"cross-domain"}}]},{"title":"Javascript URL Object","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/javascript-url-object\/","rel":"alternate"}},"published":"2013-05-20T11:00:00+03:00","updated":"2013-05-20T11:00:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-05-20:\/web-development\/javascript-url-object\/","summary":"<p>I've been doing some operations on URLs in Javascript where I needed to extract different parts from a string URL, such as the domain, port, and most importantly the parameter values. I really wished there was some function which takes a string URL and breaks it down into an ...<\/p>","content":"<p>I've been doing some operations on URLs in Javascript where I needed to extract different parts from a string URL, such as the domain, port, and most importantly the parameter values. I really wished there was some function which takes a string URL and breaks it down into an object of accessible properties automatically. What I particularly wanted in such a data structure is to have easy access to the URL's parameter values as key value pairs and store a parameters multiple values automatically into an array too.<\/p>\n<p>So I ended up writing my own function for generating such a structure for a string URL. In this implementation, there are 3 optional parameters:<\/p>\n<ul>\n<li>The URL string, if not supplied the value defaults to the current window's location.<\/li>\n<li>An unescape option to remove any escaping(for example space escape) from the parameter values, is true by default.<\/li>\n<li>A convert to number option, for converting any numeric values in the parameters from string to int or float, it true by default.<\/li>\n<\/ul>\n<p>Getting most of the URL values was done through a nice trick which is to add a hyperlink element to the DOM and theN access the values via the hyperlink object by calling its generated attributes, namely: protocol, hostname, port, hash, pathname, and search. Calling the search attribute of the URL would return a string of the parameters part of the URL, from there the job was to parse that string and its values and generate a set of key(parameter name) value(parameter value) pairs representing it. <\/p>\n<p>Here is the full implementation:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">urlObject<\/span><span class=\"p\">(<\/span><span class=\"nx\">options<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"s2\">&quot;use strict&quot;<\/span><span class=\"p\">;<\/span>\n    <span class=\"cm\">\/*global window, document*\/<\/span>\n\n    <span class=\"kd\">var<\/span> <span class=\"nx\">url_search_arr<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">option_key<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">i<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">urlObj<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">get_param<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">key<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">val<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">url_query<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">url_get_params<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{},<\/span>\n        <span class=\"nx\">a<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">document<\/span><span class=\"p\">.<\/span><span class=\"nx\">createElement<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">),<\/span>\n        <span class=\"nx\">default_options<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n            <span class=\"s1\">&#39;url&#39;<\/span><span class=\"o\">:<\/span> <span class=\"nb\">window<\/span><span class=\"p\">.<\/span><span class=\"nx\">location<\/span><span class=\"p\">.<\/span><span class=\"nx\">href<\/span><span class=\"p\">,<\/span>\n            <span class=\"s1\">&#39;unescape&#39;<\/span><span class=\"o\">:<\/span> <span class=\"kc\">true<\/span><span class=\"p\">,<\/span>\n            <span class=\"s1\">&#39;convert_num&#39;<\/span><span class=\"o\">:<\/span> <span class=\"kc\">true<\/span>\n        <span class=\"p\">};<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">typeof<\/span> <span class=\"nx\">options<\/span> <span class=\"o\">!==<\/span> <span class=\"s2\">&quot;object&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">options<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">default_options<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"nx\">option_key<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">default_options<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">default_options<\/span><span class=\"p\">.<\/span><span class=\"nx\">hasOwnProperty<\/span><span class=\"p\">(<\/span><span class=\"nx\">option_key<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">options<\/span><span class=\"p\">[<\/span><span class=\"nx\">option_key<\/span><span class=\"p\">]<\/span> <span class=\"o\">===<\/span> <span class=\"kc\">undefined<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"nx\">options<\/span><span class=\"p\">[<\/span><span class=\"nx\">option_key<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">default_options<\/span><span class=\"p\">[<\/span><span class=\"nx\">option_key<\/span><span class=\"p\">];<\/span>\n                <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">href<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">options<\/span><span class=\"p\">.<\/span><span class=\"nx\">url<\/span><span class=\"p\">;<\/span>\n    <span class=\"nx\">url_query<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">search<\/span><span class=\"p\">.<\/span><span class=\"nx\">substring<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n    <span class=\"nx\">url_search_arr<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">url_query<\/span><span class=\"p\">.<\/span><span class=\"nx\">split<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&amp;&#39;<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">url_search_arr<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"nx\">length<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">for<\/span> <span class=\"p\">(<\/span><span class=\"nx\">i<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"nx\">url_search_arr<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">;<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"nx\">get_param<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">url_search_arr<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">].<\/span><span class=\"nx\">split<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;=&quot;<\/span><span class=\"p\">);<\/span>\n\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">options<\/span><span class=\"p\">.<\/span><span class=\"nx\">unescape<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">decodeURI<\/span><span class=\"p\">(<\/span><span class=\"nx\">get_param<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]);<\/span>\n                <span class=\"nx\">val<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">decodeURI<\/span><span class=\"p\">(<\/span><span class=\"nx\">get_param<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]);<\/span>\n            <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">key<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">get_param<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">];<\/span>\n                <span class=\"nx\">val<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">get_param<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">];<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">options<\/span><span class=\"p\">.<\/span><span class=\"nx\">convert_num<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/^\\d+$\/<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"nx\">val<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">parseInt<\/span><span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">,<\/span> <span class=\"mi\">10<\/span><span class=\"p\">);<\/span>\n                <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">.<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/^\\d+\\.\\d+$\/<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n                    <span class=\"nx\">val<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">parseFloat<\/span><span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">);<\/span>\n                <span class=\"p\">}<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">===<\/span> <span class=\"kc\">undefined<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">val<\/span><span class=\"p\">;<\/span>\n            <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"k\">typeof<\/span> <span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">===<\/span> <span class=\"s2\">&quot;string&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">],<\/span> <span class=\"nx\">val<\/span><span class=\"p\">];<\/span>\n            <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n                <span class=\"nx\">url_get_params<\/span><span class=\"p\">[<\/span><span class=\"nx\">key<\/span><span class=\"p\">].<\/span><span class=\"nx\">push<\/span><span class=\"p\">(<\/span><span class=\"nx\">val<\/span><span class=\"p\">);<\/span>\n            <span class=\"p\">}<\/span>\n\n            <span class=\"nx\">get_param<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[];<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"nx\">urlObj<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">protocol<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">protocol<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">hostname<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">hostname<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">host<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">host<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">port<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">port<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">hash<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">hash<\/span><span class=\"p\">.<\/span><span class=\"nx\">substr<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span>\n        <span class=\"nx\">pathname<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">pathname<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">search<\/span><span class=\"o\">:<\/span> <span class=\"nx\">a<\/span><span class=\"p\">.<\/span><span class=\"nx\">search<\/span><span class=\"p\">,<\/span>\n        <span class=\"nx\">parameters<\/span><span class=\"o\">:<\/span> <span class=\"nx\">url_get_params<\/span>\n    <span class=\"p\">};<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"nx\">urlObj<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>And here is sample usage with a sample output:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"nt\">urlObject<\/span><span class=\"o\">(<\/span><span class=\"p\">{<\/span><span class=\"err\">&#39;url&#39;:&#39;<\/span><span class=\"n\">http<\/span><span class=\"p\">:<\/span><span class=\"o\">\/\/<\/span><span class=\"n\">localhost<\/span><span class=\"o\">.<\/span><span class=\"n\">test<\/span><span class=\"o\">?<\/span><span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"n\">ayman<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">age<\/span><span class=\"o\">=<\/span><span class=\"mi\">22<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">gpa<\/span><span class=\"o\">=<\/span><span class=\"mf\">3.5<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">course<\/span><span class=\"o\">=<\/span><span class=\"n\">programming<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">course<\/span><span class=\"o\">=<\/span><span class=\"n\">mathematics<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">course<\/span><span class=\"o\">=<\/span><span class=\"n\">algorithms<\/span><span class=\"err\">&#39;<\/span><span class=\"p\">}<\/span><span class=\"o\">);<\/span>\n<\/pre><\/div>\n\n\n<div class=\"highlight\"><pre><span><\/span><span class=\"err\">{<\/span>\n  <span class=\"ss\">&quot;protocol&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;http:&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;hostname&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;localhost.test&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;host&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;localhost.test&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;port&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;hash&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;pathname&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;\/&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;search&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;?name=ayman&amp;age=22&amp;gpa=3.5&amp;course=programming&amp;course=mathematics&amp;course=algorithms&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;parameters&quot;<\/span><span class=\"p\">:<\/span> <span class=\"err\">{<\/span>\n  <span class=\"ss\">&quot;name&quot;<\/span><span class=\"p\">:<\/span> <span class=\"ss\">&quot;ayman&quot;<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;age&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">22<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;gpa&quot;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">.<\/span><span class=\"mi\">5<\/span><span class=\"p\">,<\/span>\n  <span class=\"ss\">&quot;course&quot;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span>\n     <span class=\"ss\">&quot;programming&quot;<\/span><span class=\"p\">,<\/span>\n     <span class=\"ss\">&quot;mathematics&quot;<\/span><span class=\"p\">,<\/span>\n     <span class=\"ss\">&quot;algorithms&quot;<\/span><span class=\"p\">]<\/span>\n  <span class=\"err\">}<\/span>\n<span class=\"err\">}<\/span>\n<\/pre><\/div>\n\n\n<p>The code is also available as a Gist <a href=\"https:\/\/gist.github.com\/aymanfarhat\/5608517\">here<\/a>.<\/p>\n<p>I hope that you find this code snippet helpful in your work, would love to hear any suggestions and comments from your side about the code too. Have a good day!<\/p>\n<h2>Update (Jan 12, 2014)<\/h2>\n<p>I just updated the code above with a refactored and unit tested version of the old function. Fixed some bugs and style problems. The code conforms to <a href=\"http:\/\/www.ecma-international.org\/publications\/standards\/Ecma-262.htm\">Third Edition of the ECMAScript Programming Language Standard<\/a> via <a href=\"http:\/\/www.jslint.com\/lint.html\">JSLint<\/a>. The <a href=\"https:\/\/gist.github.com\/aymanfarhat\/5608517\">gist<\/a> is up to date and it is also available on <a href=\"http:\/\/jsfiddle.net\/aymanfarhat\/ut5kd\/1\/\">JSFiddle for testing<\/a>.<\/p>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"parameters"}},{"@attributes":{"term":"urls"}},{"@attributes":{"term":"parsing"}}]},{"title":"Serializing a Function's Arguments in Javascript","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/serializing-function-arguments-in-javascript\/","rel":"alternate"}},"published":"2013-05-13T01:00:00+03:00","updated":"2013-05-13T01:00:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-05-13:\/web-development\/serializing-function-arguments-in-javascript\/","summary":"<p>At many instances when doing Ajax requests in Javascript, a serialize function comes in handy for creating a string in standard URL-encoded notation for the request parameters. The most widely used <a href=\"http:\/\/api.jquery.com\/serialize\/\">serialize function<\/a> is that of jQuery which works great on forms. But what if the request is not based ...<\/p>","content":"<p>At many instances when doing Ajax requests in Javascript, a serialize function comes in handy for creating a string in standard URL-encoded notation for the request parameters. The most widely used <a href=\"http:\/\/api.jquery.com\/serialize\/\">serialize function<\/a> is that of jQuery which works great on forms. But what if the request is not based on values of a form?<\/p>\n<h2>Some Background<\/h2>\n<p>Consider a function who's job is to take some arguments, and perform a request with the supplied values. Also consider that there is no form involved, the first thing that comes to mind is to build the data string through concatenating the values of the arguments and we'd end up doing something like this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">requesEmployee<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span><span class=\"nx\">middle<\/span><span class=\"p\">,<\/span><span class=\"nx\">family<\/span><span class=\"p\">,<\/span><span class=\"nx\">income<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n   <span class=\"kd\">var<\/span> <span class=\"nx\">params<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;name=&quot;<\/span><span class=\"o\">+<\/span><span class=\"nx\">name<\/span><span class=\"o\">+<\/span><span class=\"s2\">&quot;&amp;middle=&quot;<\/span><span class=\"o\">+<\/span><span class=\"nx\">middle<\/span><span class=\"o\">+<\/span><span class=\"s2\">&quot;&amp;family=&quot;<\/span><span class=\"o\">+<\/span><span class=\"nx\">family<\/span><span class=\"o\">+<\/span><span class=\"s2\">&quot;&amp;income=&quot;<\/span><span class=\"o\">+<\/span><span class=\"nx\">income<\/span><span class=\"p\">;<\/span>\n\n   <span class=\"nx\">$<\/span><span class=\"p\">.<\/span><span class=\"nx\">ajax<\/span><span class=\"p\">({<\/span>\n      <span class=\"nx\">url<\/span><span class=\"o\">:<\/span><span class=\"s2\">&quot;someurl&quot;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">type<\/span><span class=\"o\">:<\/span><span class=\"s2\">&quot;GET&quot;<\/span><span class=\"p\">,<\/span>\n      <span class=\"nx\">data<\/span><span class=\"o\">:<\/span> <span class=\"nx\">params<\/span>\n   <span class=\"p\">});<\/span>\n\n   <span class=\"c1\">\/\/ etc...<\/span>\n<span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>The params string looks fine but what if there were much more parameters like 10, 15 or 20? Concatenating them would be annoying and wont look much elegant even when using something like <a href=\"http:\/\/www.diveintojavascript.com\/projects\/javascript-sprintf\">sprintf<\/a>. The ability to build such a string right from the function's argument values and names would be very powerful and that's what we're going to do.<\/p>\n<h2>Serializing through the Function's Arguments<\/h2>\n<p>As an alternative we can write a function to do the serialization for us. After all, a list of argument values on a function is easily accessible and so are the parameter names, all what we have to do after obtaining the two lists is glue them together into a string. Here is an example:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">serializeArgs<\/span><span class=\"p\">(<\/span><span class=\"nx\">func<\/span><span class=\"p\">,<\/span><span class=\"nx\">args<\/span><span class=\"p\">,<\/span><span class=\"nx\">exclude<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n   <span class=\"nx\">exclude<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">exclude<\/span> <span class=\"o\">||<\/span> <span class=\"p\">[];<\/span>\n\n   <span class=\"kd\">var<\/span> <span class=\"nx\">args<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">Array<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">slice<\/span><span class=\"p\">.<\/span><span class=\"nx\">call<\/span><span class=\"p\">(<\/span><span class=\"nx\">args<\/span><span class=\"p\">,<\/span><span class=\"mi\">0<\/span><span class=\"p\">);<\/span>\n   <span class=\"kd\">var<\/span> <span class=\"nx\">funstr<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">func<\/span><span class=\"p\">.<\/span><span class=\"nx\">toString<\/span><span class=\"p\">();<\/span>\n   <span class=\"kd\">var<\/span> <span class=\"nx\">params<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">funstr<\/span><span class=\"p\">.<\/span><span class=\"nx\">slice<\/span><span class=\"p\">(<\/span><span class=\"nx\">funstr<\/span><span class=\"p\">.<\/span><span class=\"nx\">indexOf<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;(&#39;<\/span><span class=\"p\">)<\/span><span class=\"o\">+<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"nx\">funstr<\/span><span class=\"p\">.<\/span><span class=\"nx\">indexOf<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;)&#39;<\/span><span class=\"p\">)).<\/span><span class=\"nx\">match<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/([^\\s,]+)\/g<\/span><span class=\"p\">);<\/span>\n\n   <span class=\"kd\">var<\/span> <span class=\"nx\">serialized<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">;<\/span>\n\n   <span class=\"k\">for<\/span><span class=\"p\">(<\/span><span class=\"kd\">var<\/span> <span class=\"nx\">i<\/span> <span class=\"k\">in<\/span> <span class=\"nx\">args<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"nx\">contains<\/span><span class=\"p\">(<\/span><span class=\"nx\">exclude<\/span><span class=\"p\">,<\/span><span class=\"nx\">params<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">]))<\/span> <span class=\"p\">{<\/span>\n         <span class=\"nx\">append<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"nx\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"nx\">args<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span><span class=\"o\">?<\/span><span class=\"s2\">&quot;&amp;&quot;<\/span><span class=\"o\">:<\/span><span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">;<\/span>\n         <span class=\"nx\">serialized<\/span> <span class=\"o\">+=<\/span> <span class=\"nx\">params<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">]<\/span><span class=\"o\">+<\/span><span class=\"s2\">&quot;=&quot;<\/span><span class=\"o\">+<\/span><span class=\"nx\">args<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">]<\/span><span class=\"o\">+<\/span><span class=\"nx\">append<\/span><span class=\"p\">;<\/span>\n      <span class=\"p\">}<\/span>\n   <span class=\"p\">}<\/span>\n   <span class=\"k\">return<\/span> <span class=\"nx\">serialized<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"kd\">function<\/span> <span class=\"nx\">contains<\/span><span class=\"p\">(<\/span><span class=\"nx\">arr<\/span><span class=\"p\">,<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n   <span class=\"kd\">var<\/span> <span class=\"nx\">i<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">arr<\/span><span class=\"p\">.<\/span><span class=\"nx\">length<\/span><span class=\"p\">;<\/span>\n\n   <span class=\"k\">while<\/span><span class=\"p\">(<\/span><span class=\"nx\">i<\/span><span class=\"o\">--<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n      <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"nx\">arr<\/span><span class=\"p\">[<\/span><span class=\"nx\">i<\/span><span class=\"p\">]<\/span> <span class=\"o\">===<\/span> <span class=\"nx\">obj<\/span><span class=\"p\">)<\/span>\n         <span class=\"k\">return<\/span> <span class=\"kc\">true<\/span><span class=\"p\">;<\/span>\n   <span class=\"p\">}<\/span>\n\n   <span class=\"k\">return<\/span> <span class=\"kc\">false<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>Sample usage:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">request<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span><span class=\"nx\">middle<\/span><span class=\"p\">,<\/span><span class=\"nx\">family<\/span><span class=\"p\">,<\/span><span class=\"nx\">income<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n   <span class=\"kd\">var<\/span> <span class=\"nx\">data<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">serializeArgs<\/span><span class=\"p\">(<\/span><span class=\"nx\">test<\/span><span class=\"p\">,<\/span><span class=\"nx\">arguments<\/span><span class=\"p\">,[<\/span><span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">]);<\/span>\n   <span class=\"cm\">\/* Result: name=john&amp;family=Doe&amp;income=9000 *\/<\/span>\n\n   <span class=\"cm\">\/** Rest of the code **\/<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">request<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;John&quot;<\/span><span class=\"p\">,<\/span><span class=\"s2\">&quot;Jim&quot;<\/span><span class=\"p\">,<\/span><span class=\"s2\">&quot;Doe&quot;<\/span><span class=\"p\">,<\/span><span class=\"mi\">9000<\/span><span class=\"p\">);<\/span>\n<\/pre><\/div>\n\n\n<p>the serializeArgs function takes 3 arguments, the called function, argument values, and an optional array of excluded parameters that we don't want to include within the serialized string. The argument values we're getting them for \"free\" as within any function exists a local array-like object(arguments) holding the values. As for obtaining a list of the names I converted the function into a string and sliced my way to obtain them, pretty hackish yet works well on any browser and does the job. After obtaining those two lists, building the string is a trivial, all we have to do is loop and concatenating on each index.<\/p>\n<p>The contains function is optional if you're using some library which provides that functionality, such as <a href=\"http:\/\/jquery.com\/\">jQuery<\/a> or <a href=\"http:\/\/underscorejs.org\/\">underscore<\/a>.<\/p>\n<p>I hope you find this technique useful in any of your work, would love to hear your feedback and remarks about this post, have a good day!<\/p>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"serialization"}},{"@attributes":{"term":"functions"}},{"@attributes":{"term":"parameters"}}]},{"title":"Methods Within Constructor vs Prototype in Javascript","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/methods-within-constructor-vs-prototype-in-javascript\/","rel":"alternate"}},"published":"2013-04-02T17:26:00+03:00","updated":"2013-04-02T17:26:00+03:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-04-02:\/web-development\/methods-within-constructor-vs-prototype-in-javascript\/","summary":"<p>At many instances when working with javascript objects, different pieces of code can give the same result on the surface yet underneath they could be different. One scenario is when adding methods to your Javascript 'classes'. First of all lets agree on the fact that there are no classes in ...<\/p>","content":"<p>At many instances when working with javascript objects, different pieces of code can give the same result on the surface yet underneath they could be different. One scenario is when adding methods to your Javascript 'classes'.<\/p>\n<p>First of all lets agree on the fact that there are no classes in Javascript, and what you may refer to as a class is known as a constructor. That is because Javascript is not your classic <a href=\"http:\/\/en.wikipedia.org\/wiki\/Class-based_programming\">class-based<\/a> language but rather a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Prototype-based_programming\">prototype-based<\/a> language.<\/p>\n<h2>It's not what it looks like<\/h2>\n<p>One way that may seem very natural is to set the methods right within the constructor, just like this.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">Person<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">family<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">name<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">getFull<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span> <span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot; &quot;<\/span> <span class=\"o\">+<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">};<\/span>\n<span class=\"p\">}<\/span>\n<\/pre><\/div>\n\n\n<p>Looks pretty natural for someone coming from a class based language like Java, and it will work as expected.<\/p>\n<p>Yet the truth is, this approach might be wrong for many situations. In Javascript when you bind a method to the this keyword, you are providing that method to only that particular instance and it does not really have any relationship with an object instance of that constructor, pretty much like a static method. Keeping in mind that functions are first-class citizens in Javascript, we can deal with them just like objects, in this case we're only adding a property to an instance of a function object. Thats only part of the story, you must also know that any method attached via this <strong>will get re-declared<\/strong> for every new instance we create, which could affect the memory usage of the application negatively if we wish to create so many instances.<\/p>\n<h2>All that is gold does not glitter<\/h2>\n<p>That is why it is recommended in most cases to use a less obvious approach which is through our object's <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/JavaScript\/Reference\/Global_Objects\/Object\/prototype\">prototype<\/a>. Prototype will enable us to easily define methods to all instances of the instances while saving memory. What's great is that the method will be applied to the prototype of the object, so it is only stored in the memory once, because objects coming from the same constructor point to one common prototype object. In addition to that, all instances of Person will have access to that method.<\/p>\n<p>Recreating the above example, we end up with something like this<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">Person<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">family<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">name<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"nx\">Person<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">getFull<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot; &quot;<\/span> <span class=\"o\">+<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>Now having our object instances based on the second example, we will be able to save a significant amount of memory compared to the first approach as the number of instances of the constructor grows larger within the application. One should note though that modern Javascript engines such as V8 are smart enough for not to recreate instances of a method thanks to hidden classes.<\/p>\n<p>Apart from low memory usage, the prototype approach is obviously faster in execution when creating new object instances since no time is spent on re-declaring any methods. However, there will be a slight decrease in the speed of invoking a method in comparison to the first approach. This is because when calling <code>getFull<\/code> the Javascript runtime will check for the method on the instance of the <code>Person<\/code> it won't be found there directly so it will then check the prototype of <code>Person<\/code> to find it. Yet definitely the overhead isn't that significant unless we have a deep prototype hierarchy.<\/p>\n<h2>There is no silver bullet<\/h2>\n<p>Despite the advantages of the prototype approach, it will always depend on the situation for which one to follow. For example the first approach can be useful if we needed access to local private variables from our method. In some situations we might find that we will be creating a small number of instances and accessing local object variables is part of the code design, then the first approach is not a bad choice.<\/p>\n<p>The prototype approach would still be better when there is no need for the method to access local variables and when the creation of so many object instances is expected in which memory consumption becomes a concern.<\/p>\n<h2>Putting it all together<\/h2>\n<p>Back to our Person constructor again, consider a person has a private list of bank records which we do not wish to expose publicly yet we need to get the total balance from it. At the same time we want to have a method for getting the person's name, family and balance in a single string. To achieve that we'll apply a hybrid of both approaches, we need to have some inside access within the object yet make sure to minimize our memory consumption when we can do so(via prototype methods).<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kd\">function<\/span> <span class=\"nx\">Person<\/span><span class=\"p\">(<\/span><span class=\"nx\">name<\/span><span class=\"p\">,<\/span> <span class=\"nx\">family<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">name<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span> <span class=\"o\">=<\/span> <span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"kd\">var<\/span> <span class=\"nx\">records<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[{<\/span><span class=\"nx\">type<\/span><span class=\"o\">:<\/span> <span class=\"s2\">&quot;in&quot;<\/span><span class=\"p\">,<\/span> <span class=\"nx\">amount<\/span><span class=\"o\">:<\/span> <span class=\"mi\">0<\/span><span class=\"p\">}];<\/span>\n\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">addTransaction<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">trans<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"nx\">trans<\/span><span class=\"p\">.<\/span><span class=\"nx\">hasOwnProperty<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;type&quot;<\/span><span class=\"p\">)<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"nx\">trans<\/span><span class=\"p\">.<\/span><span class=\"nx\">hasOwnProperty<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;amount&quot;<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n           <span class=\"nx\">records<\/span><span class=\"p\">.<\/span><span class=\"nx\">push<\/span><span class=\"p\">(<\/span><span class=\"nx\">trans<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">balance<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n       <span class=\"kd\">var<\/span> <span class=\"nx\">total<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n       <span class=\"nx\">records<\/span><span class=\"p\">.<\/span><span class=\"nx\">forEach<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">record<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n           <span class=\"k\">if<\/span><span class=\"p\">(<\/span><span class=\"nx\">record<\/span><span class=\"p\">.<\/span><span class=\"nx\">type<\/span> <span class=\"o\">===<\/span> <span class=\"s2\">&quot;in&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n             <span class=\"nx\">total<\/span> <span class=\"o\">+=<\/span> <span class=\"nx\">record<\/span><span class=\"p\">.<\/span><span class=\"nx\">amount<\/span><span class=\"p\">;<\/span>\n           <span class=\"p\">}<\/span>\n           <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n             <span class=\"nx\">total<\/span> <span class=\"o\">-=<\/span> <span class=\"nx\">record<\/span><span class=\"p\">.<\/span><span class=\"nx\">amount<\/span><span class=\"p\">;<\/span>\n           <span class=\"p\">}<\/span>\n       <span class=\"p\">});<\/span>\n\n        <span class=\"k\">return<\/span> <span class=\"nx\">total<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">};<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">Person<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">getFull<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n    <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">name<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot; &quot;<\/span> <span class=\"o\">+<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">family<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">};<\/span>\n\n<span class=\"nx\">Person<\/span><span class=\"p\">.<\/span><span class=\"nx\">prototype<\/span><span class=\"p\">.<\/span><span class=\"nx\">getProfile<\/span> <span class=\"o\">=<\/span> <span class=\"kd\">function<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n     <span class=\"k\">return<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">getFull<\/span><span class=\"p\">()<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot;, total balance: &quot;<\/span> <span class=\"o\">+<\/span> <span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"nx\">balance<\/span><span class=\"p\">();<\/span>\n<span class=\"p\">};<\/span>\n<\/pre><\/div>\n\n\n<p>The above example demonstrates that both approaches have their uses when it comes to working with Javascript objects. I hope you enjoyed reading this post, if you have questions, insights and further related explanations feel free to share them in the comments.<\/p>","category":[{"@attributes":{"term":"prototype"}},{"@attributes":{"term":"methods"}},{"@attributes":{"term":"constructor"}},{"@attributes":{"term":"performance"}}]},{"title":"The undefined vs null Pitfall in Javascript","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/the-undefined-vs-null-pitfall-in-javascript\/","rel":"alternate"}},"published":"2013-03-23T21:06:00+02:00","updated":"2013-03-23T21:06:00+02:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-03-23:\/web-development\/the-undefined-vs-null-pitfall-in-javascript\/","summary":"<p>Sometimes I come across JavaScript code with a lot of null checking against properties that are uninitialized, which is really wrong. Many people might think that uninitialized properties get a default value of null, but that is not the case despite having something like foo == null resulting in true, assuming ...<\/p>","content":"<p>Sometimes I come across JavaScript code with a lot of null checking against properties that are uninitialized, which is really wrong. Many people might think that uninitialized properties get a default value of null, but that is not the case despite having something like foo == null resulting in true, assuming foo is an undefined variable in this example.<\/p>\n<p>The result mentioned above is the way it is, because the == operator does <a href=\"http:\/\/en.wikipedia.org\/wiki\/Type_conversion\">type coercion<\/a> so that it can compare the two for their values. Thus when you do something like <code>foo == null<\/code> (Equality), JavaScript automatically converts it to the type null so it can carry out the comparison on two values with the same types, and obviously in this comparison the result will end up being true.<\/p>\n<p>On the other hand if you did <code>foo === null<\/code> (Identity) which checks for both type and value the result will be false which is the correct result because there is a type mismatch between the two. foo's type is undefined while null is an object. You can check that for yourself via <code>typeof(null)<\/code> and <code>typeof(undefined)<\/code>. Actually null <a href=\"http:\/\/www.2ality.com\/2011\/03\/javascript-values-not-everything-is.html\">is not really<\/a> an object but a primitive value in JavaScript. Having typeof(null) output \"object\" is considered to be a bug in the language. Despite that, the point here is that null and undefined are of different types anyways.<\/p>\n<p>A property that has no definition is undefined, which also means no value, no type and never been referenced before in the scope. On the other hand, null is where the property exists but it isn't known what its value is.<\/p>\n<p>As a general rule, it is good to use === instead of == in JavaScript when comparing values especially when there is a huge possibility that your program will end up comparing values of different types at some point. What is dangerous about == is that it performs all kinds of conversions between types which could produce unexpected results in your program.<\/p>","category":[{"@attributes":{"term":"javascript"}},{"@attributes":{"term":"null"}},{"@attributes":{"term":"undefined"}},{"@attributes":{"term":"web"}}]},{"title":"TypeScript: Enhanced Javascript","link":{"@attributes":{"href":"https:\/\/www.thecodeship.com\/web-development\/typescript-enhanced-javascript\/","rel":"alternate"}},"published":"2013-03-07T15:00:00+02:00","updated":"2013-03-07T15:00:00+02:00","author":{"name":"Ayman Farhat"},"id":"tag:www.thecodeship.com,2013-03-07:\/web-development\/typescript-enhanced-javascript\/","summary":"<p>One of the most important platforms nowadays is the web, and Javascript incorporates a large share from any web application today more than ever. As we get more into the single page applications trend and Javascript on the server (such as NodeJS), this language can't be really dealt with ...<\/p>","content":"<p>One of the most important platforms nowadays is the web, and Javascript incorporates a large share from any web application today more than ever. As we get more into the single page applications trend and Javascript on the server (such as NodeJS), this language can't be really dealt with as secondary anymore. In fact it isn't just about the web, Javascript is extensively used in cross mobile app frameworks and also making its way into the desktop, it is everywhere. Yet, there is a large number of developers, enjoying languages like C#, who don't like working with Javascript for reasons such not being a strongly typed language, and not having class structures. <\/p>\n<p>This is where <a href=\"http:\/\/www.typescriptlang.org\/\">TypeScript<\/a> kicks in.<\/p>\n<h2>How can TypeScript help?<\/h2>\n<p>TypeScript isn't a language designed to replace javascript, it's a typed superset of it. This means that JavaScript code would be valid TypeScript, and what the compiler generates is JavaScript. The language was designed with the .net developers in mind and that's why it packs many cool features you may already be using in your favorite .net language such as C#. In reality all \"features\" can be achieved in Javascript by following certain patterns. Yet an advantage other than having syntactic sugar for Javascript is that you get rid from all the boilerplate Javascript code you end up writing to achieve those patterns. MSDN have published a very nice article showing off some of TypeScript's features along with comparison against classic Javascript code. The result is concise code that is enjoyable to read and maintain. I highly recommend <a href=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/jj883955.aspx\">checking the examples out<\/a>.<\/p>\n<h2>What about Coffee Script and Dart?<\/h2>\n<p>Since the release of TypeScript there have been a lot of comparison with <a href=\"http:\/\/coffeescript.org\/\">Coffee Script<\/a> and <a href=\"http:\/\/www.dartlang.org\/\">Dart<\/a>. They're both different than each other and TypeScript. In both of those languages you're not writing any Javascript, they have their own languages that get compiled to Javascript code. On the other hand, TypeScript is a superset of Javascript where you write it just like you write Javascript, and any Javascript code is already valid TypeScript. A superset language is one that contains all the features of a given language and has been expanded or enhanced to include other features as well.<\/p>\n<h2>What's ahead?<\/h2>\n<p>In my opinion Typescript represents what Javascript is supposed to be, or will become like one day. Afterall, ECMAScript is progressing and some of the features supported in TypeScript will probably be available in ECMAScript 6 such as <a href=\"http:\/\/wiki.ecmascript.org\/doku.php?id=strawman:maximally_minimal_classes\">classes<\/a>, <a href=\"http:\/\/wiki.ecmascript.org\/doku.php?id=harmony:modules&amp;s=modules+syntax\">modules<\/a>, and <a href=\"http:\/\/wiki.ecmascript.org\/doku.php?id=harmony:arrow_function_syntax\">arrow functions<\/a>. As we head to a future dominated by Javascript, the language will keep moving on with new features. Alternatives to writing Javascript like Coffee Script are already getting popular, while some good features available in TypeScript are being weaved into ECMAScript 6. Where do you and your work stand from all what's going on? Would love to hear your opinion.<\/p>","category":[{"@attributes":{"term":"superset"}},{"@attributes":{"term":"TypeScript"}},{"@attributes":{"term":"enhanced"}}]}]}