How to Get Javascript Running Again

Treatment common JavaScript issues

  • Previous
  • Overview: Cross browser testing
  • Next

Now we'll wait at common cross-browser JavaScript problems and how to fix them. This includes information on using browser dev tools to track down and ready issues, using Polyfills and libraries to piece of work effectually problems, getting modern JavaScript features working in older browsers, and more.

The trouble with JavaScript

Historically, JavaScript was plagued with cross-browser compatibility problems — back in the 1990s, the main browser choices back so (Cyberspace Explorer and Netscape) had scripting implemented in unlike language flavors (Netscape had JavaScript, IE had JScript and besides offered VBScript as an option), and while at to the lowest degree JavaScript and JScript were compatible to some degree (both based on the ECMAScript specification), things were often implemented in conflicting, incompatible means, causing developers many nightmares.

Such incompatibility problems persisted well into the early on 2000s, as erstwhile browsers were even so being used and even so needed supporting. This is one of the main reasons why libraries like jQuery came into beingness — to abstract away differences in browser implementations (e.g. see the code snippet in How to make an HTTP request) so developers only have to write one simple bit of code (see jQuery.ajax()). jQuery (or whatever library yous are using) will then handle the differences in the groundwork, then you don't have to.

Things have improved significantly since and then; modern browsers practise a adept chore of supporting "classic JavaScript features", and the requirement to use such code has diminished equally the requirement to support older browsers has lessened (although bear in mind that they take not gone abroad altogether).

These days, about cross-browser JavaScript problems are seen:

  • When poor-quality browser-sniffing code, feature-detection lawmaking, and vendor prefix usage cake browsers from running code they could otherwise use just fine.
  • When developers brand use of new/nascent JavaScript features, modernistic Web APIs, etc.) in their code, and find that such features don't piece of work in older browsers.

We'll explore all these problems and more than below.

Fixing general JavaScript problems

As nosotros said in the previous article on HTML/CSS, you should make sure your code is working generally, before going on to concentrate on the cantankerous-browser issues. If you are non already familiar with the basics of Troubleshooting JavaScript, yous should study that article before moving on. There are a number of common JavaScript problems that yous will want to be mindful of, such as:

  • Basic syntax and logic problems (again, check out Troubleshooting JavaScript).
  • Making certain variables, etc. are divers in the right scope, and you are not running into conflicts between items alleged in different places (encounter Function scope and conflicts).
  • Defoliation most this, in terms of what scope it applies to, and therefore if its value is what you intended. Yous can read What is "this"? for a light introduction; you should also study examples like this one, which shows a typical pattern of saving a this scope to a dissever variable, then using that variable in nested functions and so you can exist sure you are applying functionality to the correct this telescopic.
  • Incorrectly using functions inside loops that iterate with a global variable (more than by and large "getting the scope wrong"). For instance, in bad-for-loop.html (come across source code), we loop through 10 iterations using a variable defined with var, each time creating a paragraph and adding an onclick event handler to it. When clicked, we desire each one to display an alert message containing its number (the value of i at the time it was created). Instead they all report i as 11 — considering the for loop does all its iterating before nested functions are invoked.

    Notation: The easiest solution is to declare the iteration variable with let instead of var—the value of i associated with the role is and then unique to each iteration. Unfortunately this does non work correctly with IE11, which is why we oasis't used this approach in the "good" for loop.

    If you want this to work correctly, you can define a function to add the handler separately, calling it on each iteration and passing it the current value of para and i each time (or something similar). Encounter good-for-loop.html (see the source code too) for a version that works.
  • Making certain asynchronous operations have returned earlier trying to use the values they render. For example, this Ajax example checks to make sure the request is complete and the response has been returned before trying to use the response for anything. This kind of operation has been fabricated easier to handle by the introduction of Promises to the JavaScript language.

Linters

As with HTML and CSS, you lot can ensure better quality, less error-prone JavaScript lawmaking using a linter, which points out errors and can too flag up warnings about bad practices, etc., and be customized to be stricter or more relaxed in their error/warning reporting. The JavaScript/ECMAScript linters nosotros'd recommend are JSHint and ESLint; these tin be used in a diversity of ways, some of which nosotros'll detail beneath.

Online

The JSHint homepage provides an online linter, which allows you to enter your JavaScript lawmaking on the left and provides an output on the right, including metrics, warnings, and errors.

Code editor plugins

It is not very convenient to have to copy and paste your code over to a web page to check its validity several times. What you actually want is a linter that will fit into your standard workflow with the minimum of hassle. Many lawmaking editors take linter plugins, for example GitHub's Atom lawmaking editor has a JSHint plugin available.

To install it:

  1. Install Atom (if y'all haven't got an upwardly-to-appointment version already installed) — download it from the Atom page linked to a higher place.
  2. Go to Atom'southward Preferences... dialog (e.g. by Choosing Atom > Preferences... on Mac, or File > Preferences... on Windows/Linux) and choose the Install option in the left-hand carte.
  3. In the Search packages text field, type "jslint" and press Enter/Return to search for linting-related packages.
  4. You should run into a package called lint at the top of the list. Install this first (using the Install button), as other linters rely on it to work. Afterward that, install the linter-jshint plugin.
  5. After the packages accept finished installing, effort loading up a JavaScript file: you'll see any problems highlighted with greenish (for warnings) and red (for errors) circles next to the line numbers, and a divide panel at the bottom provides line numbers, error letters, and sometimes suggested values or other fixes.

Other popular editors have like linting packages available. For example, see the "Plugins for text editors and IDEs" section of the JSHint install folio.

Other uses

At that place are other means to utilize such linters; you can read about them on the JSHint and ESLint install pages.

It is worth mentioning control line uses — y'all tin can install these tools as control line utilities (available via the CLI — control line interface) using npm (Node Bundle Manager — you'll accept to install NodeJS first). For example, the following command installs JSHint:

Yous tin then point these tools at JavaScript files yous want to lint, for case:

You tin besides apply these tools with a job runner/build tool such every bit Gulp or Webpack to automatically lint your JavaScript during development. (see Using a task runner to automate testing tools in a subsequently article.) Come across ESLint integrations for ESLint options; JSHint is supported out of the box by Grunt, and also has other integrations available, e.g. JSHint loader for Webpack.

Note: ESLint takes a chip more than setup and configuration than JSHint, but information technology is more powerful too.

Browser developer tools

Browser developer tools accept many useful features for helping to debug JavaScript. For a start, the JavaScript console volition study errors in your lawmaking.

Brand a local copy of our cleaved-ajax.html example (come across the source lawmaking also).

If y'all look at the console, you'll see the error message "Uncaught TypeError: tin't access property "length", heroes is undefined", and the referenced line number is 49. If nosotros look at the source lawmaking, the relevant lawmaking department is this:

                                  function                  showHeroes                  (                  jsonObj                  )                  {                  let                  heroes                  =                  jsonObj[                  'members'                  ]                  ;                  for                  (i                  =                  0                  ;                  i                  <                  heroes.length;                  i++                  )                  {                  ...                              

So the code falls over every bit soon as we endeavour to admission a property of jsonObj (which as y'all might expect, is supposed to be a JSON object). This is supposed to be fetched from an external .json file using the following XMLHttpRequest call:

                                  permit                  requestURL                  =                  'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json'                  ;                  allow                  request                  =                  new                  XMLHttpRequest                  (                  )                  ;                  request.                  open                  (                  'GET'                  ,                  requestURL)                  ;                  request.                  send                  (                  )                  ;                  allow                  superHeroes                  =                  asking.response;                  populateHeader                  (superHeroes)                  ;                  showHeroes                  (superHeroes)                  ;                              

But this fails.

The Console API

Y'all may already know what is incorrect with this code, merely let'due south explore information technology some more than to show how you could investigate this. For a start, there is a Console API that allows JavaScript code to collaborate with the browser's JavaScript panel. It has a number of features available, merely the main one you'll use often is console.log(), which prints a custom message to the console.

Try inserting the following line just below line 31 (bolded above):

                panel.                  log                  (                  'Response value: '                  +                  superHeroes)                  ;                              

Refresh the folio in the browser, and y'all will go an output in the console of "Response value:", plus the same error message we saw earlier

The console.log() output shows that the superHeroes object doesn't appear to contain annihilation. A very common problem with async requests like this is when you try to practice something with the response object before it has actually been returned from the network. Allow's fix this trouble past running the code once the load consequence has been fired — remove the console.log() line, and update this code block:

                                  let                  superHeroes                  =                  request.response;                  populateHeader                  (superHeroes)                  ;                  showHeroes                  (superHeroes)                  ;                              

to the post-obit:

                asking.                  onload                  =                  role                  (                  )                  {                  let                  superHeroes                  =                  request.response;                  populateHeader                  (superHeroes)                  ;                  showHeroes                  (superHeroes)                  ;                  }                              

To summarize, anytime something is not working and a value does not announced to exist what it is meant to be at some point in your code, you can employ console.log() to print information technology out and encounter what is happening.

Using the JavaScript debugger

Unfortunately, we nevertheless take the same fault — the trouble has not gone away. Permit'southward investigate this at present, using a more sophisticated characteristic of browser developer tools: the JavaScript debugger equally it is called in Firefox.

In Firefox, the Debugger tab looks as follows:

  • On the left, you tin select the script you lot want to debug (in this instance we accept only one).
  • The heart console shows the code in the selected script.
  • The right-hand console shows useful details pertaining to the current environment — Breakpoints, Callstack and currently active Scopes.

The main feature of such tools is the ability to add together breakpoints to code — these are points where the execution of the code stops, and at that point you can examine the environment in its current land and see what is going on.

Let'due south get to work. The error is now being thrown at line 51. Click on line number 51 in the center panel to add a breakpoint to it (you'll come across a bluish arrow announced over the height of it). At present refresh the page (Cmd/Ctrl + R) — the browser will pause execution of the code at line 51. At this point, the correct-hand side volition update to evidence some very useful information.

  • Under Breakpoints, you lot'll see the details of the suspension-point yous have prepare.
  • Under Call Stack, yous'll see a few entries — this is basically a listing of the series of functions that were invoked to crusade the current function to exist invoked. At the elevation, we have showHeroes() the part nosotros are currently in, and second we have onload, which stores the event handler function containing the call to showHeroes().
  • Under Scopes, you'll run across the currently active telescopic for the part nosotros are looking at. We merely have iii — showHeroes, cake, and Window (the global telescopic). Each scope can exist expanded to show the values of variables inside the scope when execution of the code was stopped.

We tin can find out some very useful information in here.

  1. Expand the showHeroes scope — yous tin can see from this that the heroes variable is undefined, indicating that accessing the members property of jsonObj (offset line of the function) didn't piece of work.
  2. Yous can also see that the jsonObj variable is storing a text string, not a JSON object.
  3. Exploring further down the call stack, click onload in the Call Stack section. The view will update to evidence the request.onload function in the center panel, and its scopes in the Scopes section.
  4. If you expand the onload telescopic, you'll see that the superHeroes variable is a text string also, not an object. This settles it — our XMLHttpRequest call is returning the JSON as text, not JSON.

We'd similar you lot to try fixing this problem yourself. To requite you a clue, you can either tell the XMLHttpRequest object explicitly to render JSON format, or convert the returned text to JSON after the response arrives. If you become stuck, consult our fixed-ajax.html instance.

Note: The debugger tab has many other useful features that we've not discussed here, for instance conditional breakpoints and watch expressions. For a lot more information, come across the Debugger page.

Operation issues

Equally your apps go more circuitous and yous get-go to use more JavaScript, y'all may start to run across functioning problems, especially when viewing apps on slower devices. Operation is a large topic, and we don't have fourth dimension to encompass it in detail here. Some quick tips are as follows:

  • To avoid loading more JavaScript than you need, bundle your scripts into a unmarried file using a solution like Browserify. In full general, reducing the number of HTTP requests is very proficient for operation.
  • Make your files even smaller by minifying them before y'all load them onto your production server. Minifying squashes all the code together onto a huge single line, making information technology take up far less file size. It is ugly, but you don't need to read it when it is finished! This is best done using a minification tool like Uglify (there'due south also an online version — see JSCompress.com)
  • When using APIs, brand sure you lot turn off the API features when they are not existence used; some API calls tin be really expensive on processing ability. For example, when showing a video stream, make certain it is turned off when you can't encounter it. When tracking a device'southward location using repeated Geolocation calls, make sure you turn it off when the user stops using it.
  • Animations tin be really costly for performance. A lot of JavaScript libraries provide animation capabilities programmed past JavaScript, but it is much more than toll effective to do the animations via native browser features like CSS Animations (or the nascent Spider web Animations API) than JavaScript. Read Brian Birtles' Animative like you just don't care with Chemical element.animate for some really useful theory on why animation is expensive, tips on how to improve blitheness performance, and information on the Web Animations API.

Cross-browser JavaScript bug

In this department, nosotros'll wait at some of the more common cross-browser JavaScript problems. Nosotros'll break this down into:

  • Using mod cadre JavaScript features
  • Using modernistic Web API features
  • Using bad browser sniffing code
  • Performance problems

Using modern JavaScript/API features

In the previous article we described some of the ways in which HTML and CSS errors and unrecognized features tin be handled due to the nature of the languages. JavaScript is not as permissive equally HTML and CSS however — if the JavaScript engine encounters mistakes or unrecognized syntax, more often than non it will throw errors.

There are a number of modern JavaScript language features defined in contempo versions of the specs that won't piece of work in older browsers. Some of these are syntactic carbohydrate (basically an easier, nicer way of writing what yous can already do using existing features), and some offering interesting new possibilities.

For example:

  • Promises are a great new feature for performing asynchronous operations and making sure those operations are complete before code that relies on their results is used for something else. Every bit an case, the Fetch API (a modern equivalent to XMLHTTPRequest) uses promises to fetch resources across the network and make sure that the response has been returned before they are used (for example, displaying an image inside an <img> element). They are non supported in IE at all simply are supported across all modern browsers.
  • Arrow functions provide a shorter, more convenient syntax for writing anonymous functions. For a quick case, see pointer-function.html (encounter the source code also). Arrow functions are supported across all modern browsers, except for IE.
  • Declaring strict manner at the tiptop of your JavaScript code causes it to be parsed with a stricter set of rules, meaning that more warnings and errors will be thrown, and some things will be disallowed that would otherwise exist acceptable. It is arguably a good thought to use strict mode, equally it makes for better, more efficient code, yet it has limited/patchy support beyond browsers (encounter Strict mode in browsers).
  • Typed arrays allow JavaScript lawmaking to access and manipulate raw binary data, which is necessary as browser APIs for example start to manipulate streams of raw video and audio data. These are bachelor in IE10 and above, and all modern browsers.

There are besides many new APIs appearing in recent browsers, which don't work in older browsers, for example:

  • IndexedDB API, Web Storage API, and others for storing website data on the client-side.
  • Spider web Workers API for running JavaScript in a separate thread, helping to improve performance.
  • WebGL API for existent 3D graphics.
  • Web Audio API for advanced audio manipulation.
  • WebRTC API for multi-person, real-time video/sound connectivity (e.grand. video conferencing).
  • WebVR API for engineering science virtual reality experiences in the browser (due east.g. controlling a 3D view with data input from VR Hardware)

There are a few strategies for treatment incompatibilities betwixt browsers relating to feature back up; let'southward explore the well-nigh common ones.

Note: These strategies do not exist in split up silos — you can, of course combine them as needed. For example, y'all could use characteristic detection to determine whether a feature is supported; if it isn't, you could then run code to load a polyfill or a library to handle the lack of support.

Feature detection

The idea behind feature detection is that you can run a examination to determine whether a JavaScript feature is supported in the current browser, so conditionally run code to provide an acceptable experience both in browsers that do and don't support the feature. Every bit a quick example, the Geolocation API (which exposes available location information for the device the web browser is running on) has a main entry point for its use — a geolocation property available on the global Navigator object. Therefore, you lot tin find whether the browser supports geolocation or not past using something like the following:

                                  if                  (                  "geolocation"                  in                  navigator)                  {                  navigator.geolocation.                  getCurrentPosition                  (                  function                  (                  position                  )                  {                  // evidence the location on a map, perhaps using the Google Maps API                  }                  )                  ;                  }                  else                  {                  // Requite the user a choice of static maps instead perhaps                  }                              

You could also write such a test for a CSS feature, for example by testing for the existence of chemical element.style.property (eastward.k. paragraph.style.transform !== undefined). But for both CSS and JavaScript, it is probably meliorate to employ an established feature detection library rather than writing your own all the time. Modernizr is the manufacture standard for characteristic detection tests.

As a last point, don't misfile feature detection with browser sniffing (detecting what specific browser is accessing the site) — this is a terrible practice that should be discouraged at all costs. Run across Using bad browser sniffing lawmaking, afterward, for more than details.

Annotation: Some features are known to exist undetectable — encounter Modernizr's list of Undetectables.

Note: Characteristic detection will exist covered in a lot more detail in its own dedicated article, later in the module.

Libraries

JavaScript libraries are essentially third party units of code that y'all can adhere to your page, providing y'all with a wealth of ready-made functionality that can exist used straight away, saving yous a lot of time in the process. A lot of JavaScript libraries probably came into existence because their developer was writing a set up of common utility functions to save them time when writing future projects, and decided to release them into the wild considering other people might find them useful likewise.

JavaScript libraries tend to come in a few principal varieties (some libraries will serve more than one of these purposes):

  • Utility libraries: Provide a bunch of functions to make mundane tasks easier and less ho-hum to manage. jQuery for example provides its own fully-featured selectors and DOM manipulation libraries, to let CSS-selector type selecting of elements in JavaScript and easier DOM building. It is not so important at present we accept modernistic features like Document.querySelector()/Certificate.querySelectorAll()/Node methods available beyond browsers, but it can yet be useful when older browsers demand supporting.
  • Convenience libraries: Make difficult things easier to do. For instance, the WebGL API is really complex and challenging to use when you lot write it direct, so the Iii.js library (and others) is built on height of WebGL and provides a much easier API for creating common 3D objects, lighting, textures, etc. The Service Worker API is too very circuitous to apply, so code libraries have started appearing to make common Service Worker uses-cases much easier to implement (meet the Service Worker Cookbook for several useful code samples).
  • Effects libraries: These libraries are designed to allow you to easily add special furnishings to your websites. This was more useful back when "DHTML" was a pop buzzword, and implementing an effect involved a lot of circuitous JavaScript, but these days browsers have a lot of congenital in CSS3 features and APIs to implementing effects more than easily.
  • UI libraries: Provide methods for implementing circuitous UI features that would otherwise be challenging to implement and go working cantankerous browser, for example Foundation, Bootstrap, and Material-UI (the latter is a set of components for utilise with the React framework). These tend to be used as the basis of an entire site layout; it is often hard to driblet them in merely for one UI feature.
  • Normalization libraries: Give you a simple syntax that allows you to easily complete a chore without having to worry nearly cross browser differences. The library will manipulate appropriate APIs in the background so the functionality will piece of work any the browser (in theory). For example, LocalForage is a library for client-side information storage, which provides a simple syntax for storing and retrieving data. In the background, it uses the all-time API the browser has available for storing the data, whether that is IndexedDB, Web Storage, or fifty-fifty WebSQL (which is now deprecated, but is still supported in some older versions of Safari/IE). As some other example, jQuery

When choosing a library to use, make certain that it works across the set of browsers yous want to support, and test your implementation thoroughly. Also make sure that the library is popular and well-supported, and isn't likely to just get obsolete next week. Talk to other developers to find out what they recommend, run across how much activity and how many contributors the library has on GitHub (or wherever else it is stored), etc.

Library usage at a basic level tends to consist of downloading the library's files (JavaScript, possibly some CSS or other dependencies too) and attaching them to your folio (e.m. via a <script> element), although in that location are normally many other usage options for such libraries, like installing them every bit Bower components, or including them as dependencies via the Webpack module bundler. You volition have to read the libraries' individual install pages for more data.

Note: You lot will also come up beyond JavaScript frameworks in your travels around the Web, like Ember and Athwart. Whereas libraries are often usable for solving individual problems and dropping into existing sites, frameworks tend to exist more along the lines of complete solutions for developing complex spider web applications.

Polyfills

Polyfills too consist of 3rd political party JavaScript files that y'all can drop into your project, but they differ from libraries — whereas libraries tend to enhance existing functionality and make things easier, polyfills provide functionality that doesn't exist at all. Polyfills use JavaScript or other technologies entirely to build in back up for a characteristic that a browser doesn't support natively. For example, you might utilize a polyfill like es6-promise to make promises piece of work in browsers where they are not supported natively.

Modernizr'due south list of HTML5 Cantankerous Browser Polyfills is a useful place to find polyfills for different purposes. Once again, you should research them before yous utilize them — make sure they work and are maintained.

Let's work through an exercise — in this example we will use a Fetch polyfill to provide support for the Fetch API in older browsers; however we besides need to use the es6-promise polyfill, as Fetch makes heavy employ of promises, and browsers that don't support them will nevertheless be in trouble.

  1. To become started, make a local copy of our fetch-polyfill.html case and our nice image of some flowers in a new directory. We are going to write code to fetch the flowers epitome and display it in the folio.
  2. Next, relieve a copy of the Fetch polyfill in the aforementioned directory as the HTML.
  3. Apply the polyfill scripts to the page using the post-obit code — place these higher up the existing <script> chemical element so they will be available on the page already when we start trying to apply Fetch (we are likewise loading a Promise polyfill from a CDN, as IE11 does support promises, which fetch requires):
                                              <script src=                      "https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.min.js"                      >                      <                      /script>                      <script src=                      "https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-hope.automobile.min.js"                      >                      <                      /script>                      <script src=                      "fetch.js"                      >                      <                      /script>                                      
  4. Inside the original <script>, add the following code:
  5.                                           var                      myImage                      =                      document.                      querySelector                      (                      '.my-epitome'                      )                      ;                      fetch                      (                      'flowers.jpg'                      )                      .                      and so                      (                      role                      (                      response                      )                      {                      response.                      hulk                      (                      )                      .                      then                      (                      office                      (                      myBlob                      )                      {                      var                      objectURL                      =                      URL                      .                      createObjectURL                      (myBlob)                      ;                      myImage.src                      =                      objectURL;                      }                      )                      ;                      }                      )                      ;                                      
  6. Now if you lot load it in a browser that doesn't support Fetch (IE is an obvious candidate), you should still come across the flower image appear — absurd!

Note: Again, there are many different ways to make use of the different polyfills you volition encounter — consult each polyfill's individual documentation.

I thing you might be thinking is "why should we always load the polyfill code, even if nosotros don't need information technology?" This is a good indicate — as your sites become more circuitous and you lot kickoff to use more libraries, polyfills, etc., you tin starting time to load a lot of extra code, which can start to affect performance, particularly on less-powerful devices. Information technology makes sense to only load files equally needed.

Doing this requires some extra setup in your JavaScript. Yous need some kind of a feature detection test that detects whether the browser supports the feature nosotros are trying to use:

                                  if                  (                  browserSupportsAllFeatures                  (                  )                  )                  {                  master                  (                  )                  ;                  }                  else                  {                  loadScript                  (                  'polyfills.js'                  ,                  chief)                  ;                  }                  function                  main                  (                  err                  )                  {                  // actual app code goes in here                  }                              

And so outset we run a conditional that checks whether the function browserSupportsAllFeatures() returns true. If it does, we run the primary() function, which will contain all our app'southward code. browserSupportsAllFeatures() looks similar this:

                                  function                  browserSupportsAllFeatures                  (                  )                  {                  return                  window.Hope                  &&                  window.fetch;                  }                              

Here we are testing whether the Promise object and fetch() function be in the browser. If both do, the role returns true. If the function returns false, and then we run the code within the second part of the provisional — this runs a function called loadScript(), which loads the polyfills into the folio, then runs main() after the loading has finished. loadScript() looks like this:

                                  function                  loadScript                  (                  src,                    done                  )                  {                  const                  js                  =                  document.                  createElement                  (                  'script'                  )                  ;                  js.src                  =                  src;                  js.                  onload                  =                  office                  (                  )                  {                  done                  (                  )                  ;                  }                  ;                  js.                  onerror                  =                  function                  (                  )                  {                  washed                  (                  new                  Mistake                  (                  'Failed to load script '                  +                  src)                  )                  ;                  }                  ;                  document.head.                  appendChild                  (js)                  ;                  }                              

This function creates a new <script> chemical element, and then sets its src aspect to the path nosotros specified as the kickoff argument ('polyfills.js' when we called it in the code above). When it has loaded, we run the function we specified as the 2nd statement (main()). If an mistake occurs in the loading of the script, we still call the function, but with a custom error that we can retrieve to assist debug a problem if it occurs.

Note that polyfills.js is basically the two polyfills we are using put together into ane file. We did this manually, just there are cleverer solutions that will automatically generate bundles for you — see Browserify (run into Getting started with Browserify for a basic tutorial). It is a good idea to bundle JS files into i like this — reducing the number of HTTP requests you demand to make improves the performance of your site.

You tin can see this code in action in fetch-polyfill-merely-when-needed.html (meet the source code also). Nosotros'd like to make it clear that we tin't have credit for this code — it was originally written past Philip Walton. Check out his article Loading Polyfills But When Needed for the original code, plus a lot of useful explanation around the wider subject).

Note: There are some 3rd party options to consider, for example Polyfill.io — this is a meta-polyfill library that will await at each browser'southward capabilities and utilize polyfills equally needed, depending on what APIs and JS features yous are using in your code.

JavaScript transpiling

Some other selection that is becoming popular for people that want to utilise modernistic JavaScript features now is converting code that makes use of ECMAScript 6/ECMAScript 2015 features to a version that volition work in older browsers.

Notation: This is called "transpiling" — you are not compiling code into a lower level to be run on a computer (like you would say with C lawmaking); instead, you are changing it into a syntax that exists at a like level of abstraction so it can be used in the same way, but in slightly different circumstances (in this case, transforming one flavor of JavaScript into another).

So for example, we talked nigh arrow functions (see pointer-office.html alive, and meet the source lawmaking) before in the article, which merely piece of work in the newest browsers:

Nosotros could transpile this across to a traditional onetime-fashioned anonymous office, and so it would work in older browsers:

The recommended tool for JavaScript transpiling is currently Babel. This offers transpilation capabilities for linguistic communication features that are appropriate for transpilation. For features that can't merely be easily transpiled into an older equivalent, Babel likewise offers polyfills to provide back up.

The easiest way to give Babel a try is to use the online version, which allows you to enter your source code on the left, and outputs a transpiled version on the correct.

Annotation: There are many ways to use Babel (task runners, automation tools, etc.), as you lot'll run across on the setup page.

Using bad browser sniffing code

All browsers have a user-agent string, which identifies what the browser is (version, name, Bone, etc.) In the bad only days when pretty much anybody used Netscape or Internet Explorer, developers used to apply so-called browser sniffing code to find which browser the user was using, and give them appropriate code to work on that browser.

The lawmaking used to look something like this (although this is a simplified instance):

                                  let                  ua                  =                  navigator.userAgent;                  if                  (ua.                  indexOf                  (                  'Firefox'                  )                  !==                  -                  1                  )                  {                  // run Firefox-specific code                  }                  else                  if                  (ua.                  indexOf                  (                  'Chrome'                  )                  !==                  -                  i                  )                  {                  // run Chrome-specific lawmaking                  }                              

The thought was adequately good — detect what browser is viewing the site, and run code every bit appropriate to make sure the browser volition be able to use your site OK.

Annotation: Endeavor opening upwardly your JavaScript panel at present and running navigator.userAgent, to meet what y'all get returned.

However, every bit time went on, developers started to see major problems with this approach. For a showtime, the code was error prone. What if you knew a feature didn't work in say, Firefox 10 and beneath, and implemented lawmaking to observe this, and so Firefox 11 came out — which did back up that feature? Firefox 11 probably wouldn't exist supported because it'southward non Firefox x. You'd have to change all your sniffing lawmaking regularly.

Many developers implemented bad browser sniffing lawmaking and didn't maintain it, and browsers first getting locked out of using websites containing features that they had since implemented. This became so mutual that browsers started to prevarication about what browser they were in their user-agent strings (or claim they were all browsers), to get around sniffing code. Browsers also implemented facilities to allow users to change what user-agent cord the browser reported when queried with JavaScript. This all fabricated browser sniffing even more error prone, and ultimately pointless.

The lesson to be learned here is — NEVER use browser sniffing. The only real use example for browser sniffing code in the modern day is if you are implementing a fix for a problems in a very specific version of a item browser. But even then, most bugs become fixed pretty chop-chop in browser vendor rapid release cycles. It won't come up very often. Feature detection is almost e'er a meliorate option — if y'all notice whether a feature is supported, y'all won't need to change your code when new browser versions come up out, and the tests are much more reliable.

If you come across browser sniffing when joining an existing project, expect at whether it tin exist replaced with something more sensible. Browser sniffing causes all kind of interesting bugs, similar bug 1308462.

Handling JavaScript prefixes

In the previous article, we included quite a lot of discussion most handling CSS prefixes. Well, new JavaScript implementations sometimes use prefixes too, although JavaScript uses camel case rather than hyphenation like CSS. For example, if a prefix was being used on a new jshint API object called Object:

  • Mozilla would use mozObject
  • Chrome/Opera/Safari would use webkitObject
  • Microsoft would use msObject

Here's an example, taken from our violent-theremin demo (come across source code), which uses a combination of the Sail API and the Web Audio API to create a fun (and noisy) drawing tool:

                                  const                  AudioContext                  =                  window.AudioContext                  ||                  window.webkitAudioContext;                  const                  audioCtx                  =                  new                  AudioContext                  (                  )                  ;                              

In the example of the Spider web Sound API, the central entry points to using the API were supported in Chrome/Opera via webkit prefixed versions (they now support the unprefixed versions). The easy manner to get around this state of affairs is to create a new version of the objects that are prefixed in some browsers, and make it equal to the non-prefixed version, OR the prefixed version (OR whatsoever other prefixed versions that demand consideration) — whichever one is supported by the browser currently viewing the site will exist used.

Then we use that object to manipulate the API, rather than the original one. In this case we are creating a modified AudioContext constructor, then creating a new audio context case to use for our Web Audio coding.

This design can be practical to just about any prefixed JavaScript characteristic. JavaScript libraries/polyfills besides make use of this kind of code, to abstract browser differences away from the programmer equally much as possible.

Again, prefixed features were never supposed to be used in production websites — they are subject to change or removal without alert, and crusade cantankerous browser bug. If you insist on using prefixed features, make sure y'all use the right ones. You can wait up what browsers require prefixes for different JavaScript/API features on MDN reference pages, and sites like caniuse.com. If you lot are unsure, yous tin as well discover out by doing some testing straight in browsers.

For example, endeavour going into your browser's programmer panel and starting time typing

If this feature is supported in your browser, information technology will autocomplete.

Finding assist

There are many other issues you'll encounter with JavaScript; the about important affair to know really is how to observe answers online. Consult the HTML and CSS commodity'due south Finding aid section for our all-time advice.

Summary

So that's JavaScript. Unproblematic huh? Maybe non so simple, only this article should at to the lowest degree give you lot a beginning, and some ideas on how to tackle the JavaScript-related problems you lot will come up across.

  • Previous
  • Overview: Cross browser testing
  • Next

In this module

  • Introduction to cross browser testing
  • Strategies for carrying out testing
  • Handling common HTML and CSS bug
  • Handling common JavaScript issues
  • Handling common accessibility problems
  • Implementing feature detection
  • Introduction to automatic testing
  • Setting upwards your ain examination automation environment

cardenaswores1980.blogspot.com

Source: https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript

0 Response to "How to Get Javascript Running Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel