Script Runs Again but Doesnt Select Any Additional Elements

Treatment common JavaScript problems

  • Previous
  • Overview: Cross browser testing
  • Adjacent

At present nosotros'll look at common cantankerous-browser JavaScript problems and how to ready them. This includes information on using browser dev tools to runway downwards and fix problems, using Polyfills and libraries to work around bug, 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 then (Cyberspace Explorer and Netscape) had scripting implemented in unlike language flavors (Netscape had JavaScript, IE had JScript and as well offered VBScript as an choice), and while at least JavaScript and JScript were compatible to some degree (both based on the ECMAScript specification), things were often implemented in alien, incompatible ways, causing developers many nightmares.

Such incompatibility problems persisted well into the early 2000s, every bit quondam browsers were still being used and still needed supporting. This is one of the main reasons why libraries like jQuery came into beingness — to abstruse away differences in browser implementations (e.g. see the lawmaking snippet in How to make an HTTP request) so developers only accept to write one simple bit of lawmaking (come across jQuery.ajax()). jQuery (or whatever library you are using) volition then handle the differences in the background, and so you don't have to.

Things have improved significantly since then; modern browsers do a adept chore of supporting "classic JavaScript features", and the requirement to employ such lawmaking has macerated as the requirement to support older browsers has lessened (although bear in mind that they accept non gone away altogether).

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

  • When poor-quality browser-sniffing code, feature-detection code, and vendor prefix usage block browsers from running code they could otherwise apply just fine.
  • When developers make employ of new/nascent JavaScript features, modern Spider web APIs, etc.) in their code, and find that such features don't work in older browsers.

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

Fixing general JavaScript problems

As we said in the previous article on HTML/CSS, you lot should make sure your code is working mostly, before going on to concentrate on the cross-browser issues. If you are not already familiar with the basics of Troubleshooting JavaScript, you should report that commodity before moving on. There are a number of common JavaScript problems that you volition want to be mindful of, such as:

  • Basic syntax and logic problems (again, check out Troubleshooting JavaScript).
  • Making sure variables, etc. are defined in the correct scope, and you lot are non running into conflicts between items alleged in dissimilar places (see Function scope and conflicts).
  • Confusion most this, in terms of what scope it applies to, and therefore if its value is what yous intended. You can read What is "this"? for a calorie-free introduction; you should as well written report examples similar this one, which shows a typical pattern of saving a this telescopic to a separate variable, and so using that variable in nested functions so you lot can be sure yous are applying functionality to the correct this scope.
  • Incorrectly using functions inside loops that iterate with a global variable (more than more often than not "getting the telescopic wrong"). For example, in bad-for-loop.html (run across source lawmaking), nosotros loop through ten iterations using a variable divers with var, each time creating a paragraph and adding an onclick consequence handler to it. When clicked, we desire each one to brandish 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.

    Note: The easiest solution is to declare the iteration variable with allow instead of var—the value of i associated with the function is then unique to each iteration. Unfortunately this does not work correctly with IE11, which is why we haven't used this approach in the "good" for loop.

    If y'all desire this to work correctly, you tin define a function to add together the handler separately, calling information technology on each iteration and passing it the current value of para and i each fourth dimension (or something like). See practiced-for-loop.html (see the source code likewise) for a version that works.
  • Making certain asynchronous operations have returned before trying to use the values they return. For example, this Ajax case checks to make sure the request is complete and the response has been returned before trying to employ 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, yous can ensure better quality, less error-prone JavaScript lawmaking using a linter, which points out errors and can also flag up warnings almost bad practices, etc., and be customized to exist stricter or more relaxed in their error/warning reporting. The JavaScript/ECMAScript linters we'd recommend are JSHint and ESLint; these can exist used in a diversity of ways, some of which we'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

Information technology is not very user-friendly to accept to re-create and paste your lawmaking over to a spider web folio to check its validity several times. What you really want is a linter that will fit into your standard workflow with the minimum of hassle. Many code editors have linter plugins, for instance GitHub's Atom code editor has a JSHint plugin available.

To install it:

  1. Install Cantlet (if y'all haven't got an up-to-appointment version already installed) — download it from the Atom page linked above.
  2. Go to Atom's Preferences... dialog (eastward.m. by Choosing Atom > Preferences... on Mac, or File > Preferences... on Windows/Linux) and choose the Install pick in the left-hand menu.
  3. In the Search packages text field, blazon "jslint" and press Enter/Return to search for linting-related packages.
  4. Y'all should come across a bundle called lint at the top of the list. Install this first (using the Install push), equally other linters rely on it to work. Subsequently that, install the linter-jshint plugin.
  5. After the packages take finished installing, endeavour loading up a JavaScript file: you'll run into whatsoever issues highlighted with green (for warnings) and red (for errors) circles side by side to the line numbers, and a separate panel at the bottom provides line numbers, fault messages, and sometimes suggested values or other fixes.

Other pop editors accept similar linting packages available. For example, see the "Plugins for text editors and IDEs" section of the JSHint install folio.

Other uses

There are other ways to use such linters; you can read about them on the JSHint and ESLint install pages.

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

Y'all can so point these tools at JavaScript files you want to lint, for example:

Y'all can also use these tools with a task runner/build tool such as Gulp or Webpack to automatically lint your JavaScript during evolution. (run into Using a job runner to automate testing tools in a later 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.

Notation: ESLint takes a bit more setup and configuration than JSHint, just it is more powerful too.

Browser programmer tools

Browser developer tools take many useful features for helping to debug JavaScript. For a get-go, the JavaScript console will written report errors in your code.

Make a local copy of our broken-ajax.html example (see the source code too).

If you look at the panel, you'll come across the error bulletin "Uncaught TypeError: can't access property "length", heroes is undefined", and the referenced line number is 49. If we look at the source code, the relevant lawmaking section is this:

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

So the lawmaking falls over as soon as we endeavour to access a property of jsonObj (which as you might expect, is supposed to exist a JSON object). This is supposed to exist fetched from an external .json file using the following XMLHttpRequest call:

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

Simply this fails.

The Panel API

You may already know what is wrong with this code, but allow's explore it some more to bear witness how you could investigate this. For a starting time, there is a Console API that allows JavaScript lawmaking to interact with the browser's JavaScript panel. It has a number of features available, but the main one y'all'll employ frequently is console.log(), which prints a custom message to the console.

Effort inserting the following line just beneath line 31 (bolded to a higher place):

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

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

The console.log() output shows that the superHeroes object doesn't appear to contain anything. A very common trouble with async requests like this is when you try to do something with the response object before information technology has actually been returned from the network. Let'due south fix this problem by running the lawmaking once the load event has been fired — remove the panel.log() line, and update this lawmaking block:

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

to the following:

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

To summarize, someday something is not working and a value does non appear to be what information technology is meant to be at some signal in your code, y'all can utilize panel.log() to print it out and see what is happening.

Using the JavaScript debugger

Unfortunately, we still have the same error — the problem has not gone away. Let's investigate this now, using a more sophisticated feature of browser developer tools: the JavaScript debugger as information technology is called in Firefox.

In Firefox, the Debugger tab looks as follows:

  • On the left, you can select the script you want to debug (in this example we accept simply i).
  • The center panel shows the lawmaking in the selected script.
  • The right-hand panel shows useful details pertaining to the current environment — Breakpoints, Callstack and currently active Scopes.

The primary characteristic of such tools is the ability to add breakpoints to code — these are points where the execution of the code stops, and at that point y'all can examine the environment in its current state and encounter what is going on.

Let's go to piece of work. The error is at present being thrown at line 51. Click on line number 51 in the center panel to add a breakpoint to it (you'll meet a bluish arrow appear over the top of it). Now refresh the page (Cmd/Ctrl + R) — the browser will suspension execution of the code at line 51. At this point, the right-manus side will update to testify some very useful data.

  • Under Breakpoints, you'll run across the details of the break-indicate yous have fix.
  • Under Telephone call Stack, you'll run across a few entries — this is basically a list of the serial of functions that were invoked to crusade the current role to be invoked. At the top, we have showHeroes() the function we are currently in, and second we have onload, which stores the event handler function containing the call to showHeroes().
  • Under Scopes, you'll run into the currently active scope for the function we are looking at. We just have iii — showHeroes, block, and Window (the global scope). Each scope can be expanded to prove the values of variables inside the scope when execution of the code was stopped.

Nosotros tin can observe out some very useful information in here.

  1. Expand the showHeroes scope — yous tin meet from this that the heroes variable is undefined, indicating that accessing the members property of jsonObj (first line of the function) didn't piece of work.
  2. You can also run across that the jsonObj variable is storing a text string, not a JSON object.
  3. Exploring further downwards the call stack, click onload in the Call Stack section. The view will update to show the asking.onload office in the middle panel, and its scopes in the Scopes section.
  4. If you expand the onload scope, you'll see that the superHeroes variable is a text string too, non an object. This settles it — our XMLHttpRequest call is returning the JSON every bit text, not JSON.

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

Note: The debugger tab has many other useful features that we've not discussed here, for case conditional breakpoints and sentinel expressions. For a lot more data, meet the Debugger page.

Performance issues

Equally your apps go more circuitous and you start to use more JavaScript, yous may commencement to come across performance problems, particularly when viewing apps on slower devices. Performance is a big topic, and we don't have time to embrace it in detail here. Some quick tips are as follows:

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

Cross-browser JavaScript problems

In this section, we'll look at some of the more than common cross-browser JavaScript issues. We'll interruption this downwards into:

  • Using modern core JavaScript features
  • Using modern Web API features
  • Using bad browser sniffing code
  • Performance problems

Using modern JavaScript/API features

In the previous commodity 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 as HTML and CSS however — if the JavaScript engine encounters mistakes or unrecognized syntax, more than frequently than not information technology will throw errors.

There are a number of mod JavaScript language features divers in recent versions of the specs that won't piece of work in older browsers. Some of these are syntactic sugar (basically an easier, nicer way of writing what you can already practice using existing features), and some offer 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. As an example, the Fetch API (a modern equivalent to XMLHTTPRequest) uses promises to fetch resources across the network and brand sure that the response has been returned before they are used (for example, displaying an image inside an <img> element). They are not 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 instance, encounter arrow-function.html (run across the source code likewise). Arrow functions are supported across all modern browsers, except for IE.
  • Declaring strict style at the peak 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 be adequate. It is arguably a good idea to utilize strict mode, every bit it makes for better, more than efficient code, however information technology has limited/patchy back up across browsers (see Strict mode in browsers).
  • Typed arrays allow JavaScript code to access and dispense 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 modernistic browsers.

There are likewise many new APIs appearing in contempo browsers, which don't work in older browsers, for instance:

  • IndexedDB API, Web Storage API, and others for storing website data on the customer-side.
  • Spider web Workers API for running JavaScript in a divide thread, helping to ameliorate performance.
  • WebGL API for real 3D graphics.
  • Web Audio API for advanced audio manipulation.
  • WebRTC API for multi-person, real-fourth dimension video/audio connectivity (e.g. video conferencing).
  • WebVR API for engineering virtual reality experiences in the browser (e.1000. decision-making a 3D view with data input from VR Hardware)

In that location are a few strategies for treatment incompatibilities between browsers relating to feature support; allow's explore the most mutual ones.

Note: These strategies exercise not exist in divide silos — you can, of course combine them every bit needed. For example, you could utilise feature detection to determine whether a feature is supported; if it isn't, you could and so run code to load a polyfill or a library to handle the lack of support.

Characteristic detection

The idea behind feature detection is that y'all tin run a test to decide whether a JavaScript feature is supported in the current browser, and then conditionally run lawmaking to provide an acceptable experience both in browsers that do and don't support the feature. As a quick example, the Geolocation API (which exposes available location data for the device the web browser is running on) has a chief entry point for its utilise — a geolocation holding bachelor on the global Navigator object. Therefore, you tin detect whether the browser supports geolocation or not by using something like the following:

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

You lot could also write such a test for a CSS feature, for instance by testing for the beingness of chemical element.style.property (eastward.g. paragraph.way.transform !== undefined). Only for both CSS and JavaScript, it is probably better to use an established feature detection library rather than writing your ain all the fourth dimension. Modernizr is the industry standard for characteristic detection tests.

As a final bespeak, 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 code, afterward, for more details.

Note: Some features are known to be undetectable — see Modernizr's listing of Undetectables.

Note: Feature detection volition be covered in a lot more detail in its own defended article, later in the module.

Libraries

JavaScript libraries are essentially 3rd political party units of lawmaking that y'all can adhere to your page, providing you with a wealth of ready-made functionality that tin can be used straight away, saving you lot a lot of time in the procedure. A lot of JavaScript libraries probably came into existence because their developer was writing a set of common utility functions to save them time when writing hereafter projects, and decided to release them into the wild because other people might detect them useful too.

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

  • Utility libraries: Provide a bunch of functions to brand mundane tasks easier and less deadening to manage. jQuery for case provides its own fully-featured selectors and DOM manipulation libraries, to permit CSS-selector type selecting of elements in JavaScript and easier DOM building. It is non so of import now we accept modern features like Document.querySelector()/Document.querySelectorAll()/Node methods available across browsers, but it tin can still be useful when older browsers need supporting.
  • Convenience libraries: Make hard things easier to do. For example, the WebGL API is really complex and challenging to use when you write it directly, so the Three.js library (and others) is congenital on top of WebGL and provides a much easier API for creating common 3D objects, lighting, textures, etc. The Service Worker API is likewise very complex to apply, and so code libraries accept started actualization to brand common Service Worker uses-cases much easier to implement (see the Service Worker Cookbook for several useful lawmaking samples).
  • Furnishings libraries: These libraries are designed to let you to hands add special furnishings to your websites. This was more useful back when "DHTML" was a popular buzzword, and implementing an issue involved a lot of circuitous JavaScript, but these days browsers accept a lot of congenital in CSS3 features and APIs to implementing effects more easily.
  • UI libraries: Provide methods for implementing complex UI features that would otherwise be challenging to implement and get working cantankerous browser, for example Foundation, Bootstrap, and Cloth-UI (the latter is a set of components for use with the React framework). These tend to be used as the basis of an entire site layout; information technology is often hard to driblet them in just for one UI feature.
  • Normalization libraries: Give you a unproblematic syntax that allows you lot to hands consummate a chore without having to worry about cantankerous browser differences. The library volition manipulate appropriate APIs in the groundwork so the functionality will piece of work whatever the browser (in theory). For example, LocalForage is a library for client-side data storage, which provides a uncomplicated syntax for storing and retrieving data. In the background, information technology uses the best API the browser has bachelor for storing the information, whether that is IndexedDB, Web Storage, or fifty-fifty WebSQL (which is now deprecated, just is still supported in some older versions of Safari/IE). As some other example, jQuery

When choosing a library to use, make sure that it works across the set of browsers you want to support, and examination your implementation thoroughly. Besides brand sure that the library is popular and well-supported, and isn't likely to just become obsolete adjacent week. Talk to other developers to find out what they recommend, see how much activity and how many contributors the library has on GitHub (or wherever else information technology 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 page (e.1000. via a <script> chemical element), although there are commonly many other usage options for such libraries, like installing them as Bower components, or including them as dependencies via the Webpack module bundler. You lot volition take to read the libraries' individual install pages for more information.

Notation: You will also come up beyond JavaScript frameworks in your travels effectually the Web, like Ember and Angular. Whereas libraries are often usable for solving individual problems and dropping into existing sites, frameworks tend to be more forth the lines of consummate solutions for developing complex web applications.

Polyfills

Polyfills also consist of 3rd party JavaScript files that y'all tin drop into your project, but they differ from libraries — whereas libraries tend to enhance existing functionality and brand things easier, polyfills provide functionality that doesn't be at all. Polyfills use JavaScript or other technologies entirely to build in support for a feature that a browser doesn't support natively. For example, you might utilise a polyfill similar es6-promise to make promises work in browsers where they are not supported natively.

Modernizr's list of HTML5 Cross Browser Polyfills is a useful identify to find polyfills for different purposes. Again, yous should research them before you use them — brand certain they work and are maintained.

Let's piece of work through an exercise — in this example we volition use a Fetch polyfill to provide support for the Fetch API in older browsers; withal we also demand to utilise the es6-promise polyfill, as Fetch makes heavy use of promises, and browsers that don't support them will still be in trouble.

  1. To get started, make a local copy of our fetch-polyfill.html instance and our nice image of some flowers in a new directory. We are going to write code to fetch the flowers prototype and display it in the page.
  2. Next, salve a copy of the Fetch polyfill in the same directory as the HTML.
  3. Use the polyfill scripts to the folio using the post-obit code — place these above the existing <script> element and then they will be bachelor on the page already when nosotros offset trying to use Fetch (nosotros are besides loading a Promise polyfill from a CDN, as IE11 does back up promises, which fetch requires):
                                              <script src=                      "https://cdn.jsdelivr.net/npm/es6-hope@4/dist/es6-promise.min.js"                      >                      <                      /script>                      <script src=                      "https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.automobile.min.js"                      >                      <                      /script>                      <script src=                      "fetch.js"                      >                      <                      /script>                                      
  4. Inside the original <script>, add the following code:
  5.                                           var                      myImage                      =                      document.                      querySelector                      (                      '.my-image'                      )                      ;                      fetch                      (                      'flowers.jpg'                      )                      .                      then                      (                      function                      (                      response                      )                      {                      response.                      blob                      (                      )                      .                      so                      (                      office                      (                      myBlob                      )                      {                      var                      objectURL                      =                      URL                      .                      createObjectURL                      (myBlob)                      ;                      myImage.src                      =                      objectURL;                      }                      )                      ;                      }                      )                      ;                                      
  6. Now if you lot load it in a browser that doesn't back up Fetch (IE is an obvious candidate), y'all should still run across the flower paradigm announced — cool!

Note: Over again, there are many dissimilar ways to brand apply of the different polyfills you will encounter — consult each polyfill's individual documentation.

One thing you might be thinking is "why should nosotros ever load the polyfill code, even if nosotros don't need information technology?" This is a skilful betoken — as your sites get more circuitous and y'all commencement to use more libraries, polyfills, etc., you tin get-go to load a lot of extra code, which can start to touch performance, especially on less-powerful devices. It makes sense to only load files as needed.

Doing this requires some actress setup in your JavaScript. You need some kind of a feature detection examination that detects whether the browser supports the feature we are trying to apply:

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

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

                                  part                  browserSupportsAllFeatures                  (                  )                  {                  return                  window.Promise                  &&                  window.fetch;                  }                              

Here nosotros are testing whether the Promise object and fetch() function exist in the browser. If both do, the part returns true. If the part returns false, then we run the code inside the 2d part of the provisional — this runs a part chosen loadScript(), which loads the polyfills into the page, then runs main() after the loading has finished. loadScript() looks like this:

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

This function creates a new <script> element, and so sets its src aspect to the path nosotros specified as the beginning argument ('polyfills.js' when we called information technology in the code higher up). When it has loaded, we run the function nosotros specified as the second argument (main()). If an error occurs in the loading of the script, we still telephone call the function, but with a custom error that we can remember to help debug a problem if it occurs.

Notation that polyfills.js is basically the 2 polyfills we are using put together into ane file. We did this manually, merely there are cleverer solutions that will automatically generate bundles for you — come across Browserify (run across Getting started with Browserify for a bones tutorial). It is a proficient thought to package JS files into i like this — reducing the number of HTTP requests you need to make improves the operation of your site.

You tin can run into this code in action in fetch-polyfill-only-when-needed.html (see the source code also). We'd similar to brand it clear that we can't take credit for this code — it was originally written by Philip Walton. Check out his article Loading Polyfills Only When Needed for the original lawmaking, plus a lot of useful explanation effectually the wider subject field).

Note: There are some tertiary party options to consider, for example Polyfill.io — this is a meta-polyfill library that will look at each browser's capabilities and apply polyfills as needed, depending on what APIs and JS features yous are using in your lawmaking.

JavaScript transpiling

Another option that is becoming popular for people that desire to use modern JavaScript features now is converting code that makes use of ECMAScript 6/ECMAScript 2015 features to a version that volition work in older browsers.

Annotation: This is called "transpiling" — yous are non compiling code into a lower level to exist run on a estimator (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 tin can be used in the same manner, but in slightly unlike circumstances (in this case, transforming ane season of JavaScript into another).

And then for example, we talked nearly arrow functions (encounter pointer-function.html live, and see the source code) earlier in the article, which only work in the newest browsers:

We could transpile this across to a traditional onetime-fashioned bearding function, so it would piece of work in older browsers:

The recommended tool for JavaScript transpiling is currently Babel. This offers transpilation capabilities for language features that are appropriate for transpilation. For features that tin can't only exist easily transpiled into an older equivalent, Babel too offers polyfills to provide support.

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

Note: There are many means to use Babel (task runners, automation tools, etc.), equally y'all'll see on the setup folio.

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 everyone used Netscape or Internet Explorer, developers used to use so-called browser sniffing lawmaking to detect which browser the user was using, and give them advisable code to work on that browser.

The code used to look something similar this (although this is a simplified instance):

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

The thought was fairly practiced — detect what browser is viewing the site, and run code as appropriate to make sure the browser will be able to use your site OK.

Note: Try opening upward your JavaScript console at present and running navigator.userAgent, to see what you lot get returned.

However, as time went on, developers started to see major problems with this approach. For a start, the code was mistake decumbent. What if you knew a characteristic didn't work in say, Firefox 10 and below, and implemented lawmaking to observe this, and then Firefox 11 came out — which did support that feature? Firefox 11 probably wouldn't exist supported because it's not Firefox 10. Yous'd have to alter all your sniffing lawmaking regularly.

Many developers implemented bad browser sniffing code and didn't maintain information technology, and browsers start getting locked out of using websites containing features that they had since implemented. This became so common that browsers started to prevarication about what browser they were in their user-amanuensis strings (or claim they were all browsers), to get around sniffing code. Browsers likewise implemented facilities to let users to change what user-agent string the browser reported when queried with JavaScript. This all made browser sniffing even more mistake prone, and ultimately pointless.

The lesson to exist learned hither is — NEVER use browser sniffing. The but real employ case for browser sniffing code in the modernistic mean solar day is if you are implementing a fix for a bug in a very specific version of a particular browser. But even so, about bugs get fixed pretty speedily in browser vendor rapid release cycles. Information technology won't come up very ofttimes. Feature detection is almost always a better pick — if you detect whether a feature is supported, you won't need to change your lawmaking when new browser versions come up out, and the tests are much more than reliable.

If y'all come beyond browser sniffing when joining an existing project, await at whether it can exist replaced with something more than sensible. Browser sniffing causes all kind of interesting bugs, like bug 1308462.

Handling JavaScript prefixes

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

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

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

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

In the instance of the Web Audio API, the key entry points to using the API were supported in Chrome/Opera via webkit prefixed versions (they now support the unprefixed versions). The like shooting fish in a barrel way to get effectually this situation is to create a new version of the objects that are prefixed in some browsers, and brand it equal to the not-prefixed version, OR the prefixed version (OR any other prefixed versions that need consideration) — whichever one is supported by the browser currently viewing the site will exist used.

Then we use that object to dispense the API, rather than the original 1. In this case nosotros are creating a modified AudioContext constructor, then creating a new audio context instance to utilise for our Spider web Sound coding.

This blueprint tin be applied to simply nearly any prefixed JavaScript characteristic. JavaScript libraries/polyfills also make use of this kind of code, to abstruse browser differences away from the programmer as much every bit possible.

Once more, prefixed features were never supposed to be used in production websites — they are field of study to change or removal without warning, and cause cantankerous browser issues. If you insist on using prefixed features, make sure yous use the correct ones. You can look up what browsers require prefixes for unlike JavaScript/API features on MDN reference pages, and sites like caniuse.com. If you are unsure, yous tin also find out by doing some testing straight in browsers.

For instance, endeavor going into your browser'due south programmer panel and start typing

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

Finding aid

There are many other bug you'll encounter with JavaScript; the most important thing to know actually is how to find answers online. Consult the HTML and CSS article's Finding help section for our all-time advice.

Summary

And then that's JavaScript. Unproblematic huh? Maybe non so uncomplicated, but this commodity should at least give you a kickoff, and some ideas on how to tackle the JavaScript-related problems you volition come across.

  • Previous
  • Overview: Cross browser testing
  • Next

In this module

  • Introduction to cantankerous browser testing
  • Strategies for carrying out testing
  • Handling mutual HTML and CSS bug
  • Treatment mutual JavaScript problems
  • Handling common accessibility problems
  • Implementing feature detection
  • Introduction to automated testing
  • Setting upwards your own examination automation surround

knapploortambel.blogspot.com

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

0 Response to "Script Runs Again but Doesnt Select Any Additional Elements"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel