Computer Coding
Home |  ColdFusion |  IBM |  Java |  JavaScript |  Spring |  Misc |  Sign in



HTML5Rocks


Collecting and Iterating, the ES6 Way

The ECMAScript 6 specification, while still in draft form, brings the promise of many exciting new tools to add to the JavaScript programmer?s belt. New classes such as Sets and Maps offer native solutions to working with specific types of collections, and the for...of statement provides an elegant alternative to traditional ways of iterating over data.

Sets offer a way of keeping track of a collection of items in which each item can appear at most once. Maps offer more functionality than was previously possible by using Objects to associate keys with values?with Maps, your keys don?t have to be strings, and you don?t have to worry about accidentally choosing a key name that clashes with an Object?s method names. Lookup operations on native Maps and Sets are done in constant time, which offers efficiency gains over what?s possible with simulated implementations.

The following sample demonstrates constructing a Set, and using for...of to iterate over its elements:

<pre id="log"></pre>

<script>
  function log() {
    document.querySelector('#log').textContent += Array.prototype.join.call(arguments, '') + '\n';
  }

  log('Creating, using, and iterating over a Set:');
  var randomIntegers = new Set();
  // Generate a random integer in the range [1..10] five times,
  // and use a Set to keep track of the distinct integers that were generated.
  for (var i = 0; i < 5; i++) {
    randomIntegers.add(Math.floor(Math.random() * 10) + 1);
  }
  log(randomIntegers.size, ' distinct integers were generated.');
  log('The number 10 was ', randomIntegers.has(10) ? '' : 'not ', 'one of them.');
  log('Here\'s all of them:');
  // Use for...of to iterate over the items in the Set.
  // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iteration-statements
  // The Set iterator yields a single value corresponding to each entry in the Set.
  for (var item of randomIntegers) {
    log(item);
  }
</script>

Here?s a corresponding sample that illustrates using and iterating over a Map:

<script>
  log('\nCreating and iterating over a Map:');
  // Maps can be initialized by passing in an iterable value (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-iterable)
  // Here, we use an Array of Arrays to initialize. The first value in each sub-Array is the new
  // Map entry's key, and the second is the item's value.
  var typesOfKeys = new Map([
    ['one', 'My key is a string.'],
    ['1', 'My key is also a string'],
    [1, 'My key is a number'],
    [document.querySelector('#log'), 'My key is an object']
  ]);
  // You can also call set() to add new keys/values to an existing Map.
  typesOfKeys.set('!!!!', 'My key is excited!');

  // Use for...of to iterate over the items in the Map.
  // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iteration-statements
  // There are several types of Map iterators available.
  // typesOfKeys.keys() can be used to iterate over just the keys:
  log('Just the keys:');
  for (var key of typesOfKeys.keys()) {
    log('  key: ', key);
  }

  // typesOfKeys.values() can be used to iterate over just the values:
  log('Just the values:');
  for (var value of typesOfKeys.values()) {
    log('  value: ', value);
  }

  // The default Map iterator yields an Array with two items; the first is the Map entry's key and the
  // second is the Map entry's value. This default iterator is equivalent to typesOfKeys.entries().
  log('Keys and values:');
  // Alternative, ES6-idiomatic syntax currently supported in Safari & Firefox:
  // for ([key, value] of typesOfKeys) { ? } 
  for (var item of typesOfKeys) {
    log('  ', item[0], ' -> ', item[1]);
  }
</script>

Some browsers, like Chrome, Internet Explorer, and Firefox have already added support for Sets and Maps. Native support complemented by polyfill libraries like es6-collections means that JavaScript developers can start building with these new collection types today. There are no polyfills available for the for...of statement (though it is possible to transpile support via Traceur), but native support is available today in Chrome and Firefox.


Easier ArrayBuffer <-> String conversion with the Encoding API

Over two years ago, Renato Mangini described a method for converting between raw ArrayBuffers and the corresponding string representation of that data. At the end of the post, Renato mentioned that an official standardized API to handle the conversion was in the process of being drafted. The specification has now matured, and both Firefox and Google Chrome have added native support for the TextDecoder and TextEncoder interfaces.

As demonstrated by this live sample, excerpted below, the Encoding API makes it simple to translate between raw bytes and native JavaScript strings, regardless of which of the many standard encodings you need to work with.

<pre id="results"></pre>

<script>
  // The local files to be fetched, mapped to the encoding that they're using.
  var filesToEncoding = {
    'utf8.bin': 'utf-8',
    'utf16le.bin': 'utf-16le',
    'macintosh.bin': 'macintosh'
  };

  Object.keys(filesToEncoding).forEach(function(file) {
    fetchAndDecode(file, filesToEncoding[file]);
  });

  // Use XHR to fetch `file` and interpret its contents as being encoded with `encoding`.
  function fetchAndDecode(file, encoding) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', file);
    // Using 'arraybuffer' as the responseType ensures that the raw data is returned,
    // rather than letting XMLHttpRequest decode the data first.
    xhr.responseType = 'arraybuffer';
    xhr.onload = function() {
      if (this.status == 200) {
        // The decode() method takes a DataView as a parameter, which is a wrapper on top of the ArrayBuffer.
        var dataView = new DataView(this.response);
        // The TextDecoder interface is documented at http://encoding.spec.whatwg.org/#interface-textdecoder
        var decoder = new TextDecoder(encoding);
        var decodedString = decoder.decode(dataView);
        // Add the decoded file's text to the <pre> element on the page.
        document.querySelector('#results').textContent += decodedString + '\n';
      } else {
        console.error('Error while requesting', file, this);
      }
    };
    xhr.send();
  }
</script>

The text-encoding library that Renato mentioned in his original article is still a good choice for most use cases. The library uses the native methods on browsers that support them, and offers polyfills for the Encoding API on browsers that haven?t yet added support.


Web Audio Changes in m36

Web Audio changes

At Google, we love standards. We?re on a mission to build out the standards-defined Web platform. One of the small warts on that for some time has been the webkit- prefixed implementation of the Web Audio API (notably the webkitAudioContext object), and some of the deprecated bits of Web Audio that we?ve continued to support.

It was originally planned that m36 would remove support for the prefixed webkitAudioContext, since we had begun supporting the unprefixed AudioContext object. This turned out to be more troublesome than expected, so m36 supports both unprefixed and prefixed - however, even in the reintroduced webkitAudioContext, several legacy methods and attributes like createGainNode and createJavaScriptNode have been removed. In short, in m36 webkitAudioContext and AudioContext are aliases of each other; there is no difference in functionality between the two.

We will remove the support for the prefix completely after m36, likely in a couple of releases. We'll make an announcement here when the change is imminent, and we are continuing to reach out to authors to fix their Web Audio applications.

Why have we done this, rather than reverting to the previous implementation? Well, in part, we?ve been reticent to move too far backwards; we?ve already removed those APIs, and as a nice side-effect to this aliasing, applications can then work nicely on Firefox, which has never supported a prefixed AudioContext object (and quite right, too!) in their Web Audio support initially released last fall.

The rest of this update provides a guide to fixing things that may be broken in your code due to this change. The great thing about fixing these problems is that your code is then quite likely to just work in Firefox, too! (I?d thought for a long time that my Vocoder application was broken due to Firefox?s implementation, but it turned out to be one of these problems!)

If you just want to get up and running, you may want to take a look at a monkey-patch library I wrote for applications that were written to the old Web Audio code - this can help you get up and running in a minimum amount of time, as it will alias the objects and methods appropriately. Indeed, the patches the library lists is a good guide to the things that have changed.

First and foremost:

Any references to window.webkitAudioContext should be made to window.AudioContext instead. Frequently, this has been fixed with a simple:

window.AudioContext = window.AudioContext || window.webkitAudioContext;

If your app is responding with something like ?Unfortunately, your browser does not support Web Audio. Please use Chrome or Safari.? - it?s quite likely explicitly looking for webkitAudioContext. Bad developer! You could have been supporting Firefox for months!

But there are a few other, more subtle code removals, some of which can be less obvious.

  • The BiquadFilter enumerated type constants for the .type attribute (which is now a string) no longer appear on the BiquadFilterNode object, and we do not support them on the .type attribute. So you don?t use .LOWPASS (or 0) anymore - you set it to ?lowpass?.
  • Also, the Oscillator.type attribute is similarly now a string enumerated type - no more .SAWTOOTH.
  • PannerNode.type is also now a string enumerated type.
  • PannerNode.distanceModel is also now a string enumerated type.
  • createGainNode was renamed to createGain
  • createDelayNode was renamed to createDelay
  • createJavaScriptNode was renamed to createScriptProcessor
  • AudioBufferSourceNode.noteOn() is now replaced by start()
  • AudioBufferSourceNode.noteGrainOn() is also now replaced by start()
  • AudioBufferSourceNode.noteOff() is renamed to stop()
  • OscillatorNode.noteOn() is renamed to start()
  • OscillatorNode.noteOff() is renamed to stop()
  • AudioParam.setTargetValueAtTime() is renamed to setTargetAtTime()
  • `AudioContext.createWaveTable()andOscillatorNode.setWaveTable()are now renamedcreatePeriodicWave() and setPeriodicWave().
  • AudioBufferSourceNode.looping was removed, in favor of .loop
  • AudioContext.createBuffer(ArrayBuffer, boolean) to synchronously decode a blob of encoded audio data has been removed. Synchronous calls that take a long time to complete are poor coding practice; use the asynchronous decodeAudioData call instead. This is one of the more challenging changes - you need to actually change logic flow - but a far better practice. Mozilla's Ehsan Angkari wrote a nice example of how to do this in their post on converting to standard Web Audio.

Many of these (like the renaming of createGainNode, and the removal of the synchronous decoding in createBuffer) will obviously show up in the developer tools console as an error - however, some others, like this usage:

myFilterNode.type = myFilterNode.BANDPASS;

will not show up at all, and silently fail (myFilterNode.BANDPASS will now resolve to undefined, and the attempt to set .type to undefined will simply fail to produce any effect. This, by the way, was what was causing the vocoder to fail.) Likewise, just assigning the filter.type to a number used to work:

myFilterNode.type = 2;

But now, you need to use the string enumeration:

myFilterNode.type = ?bandpass?;

So, you may wish to grep your code for the following terms:

  • webkitAudioContext
  • .LOWPASS
  • .HIGHPASS
  • .BANDPASS
  • .LOWSHELF
  • .HIGHSHELF
  • .PEAKING
  • .NOTCH
  • .ALLPASS
  • .SINE
  • .SQUARE
  • .SAWTOOTH
  • .TRIANGLE
  • .noteOn
  • .noteGrainOn
  • .noteOff
  • .setWaveTable
  • .createWaveTable
  • .looping
  • .EQUALPOWER
  • .HRTF
  • .LINEAR
  • .INVERSE
  • .EXPONENTIAL
  • createGainNode
  • createDelayNode
  • .type (yes, this will have lots of false positives - but it?s the only way to catch the last example above!)

Once more, if you're in a hurry and want to get up and running, just grab a copy of my monkeypatch webkitAudioContext library and include it in your application. Happy Audio Hacking!


dialog element: shipped in Chrome 37 Beta

Chrome Beta has landed its native support for <dialog> element without needing "Enable experimental Web Platform features." flag turned on.

<dialog>
  <p>This is da dialog!</p>
  <button id="close">Close</button>
</dialog>
<button id="show">Open Dialog!</button>
<script>
  var dialog = document.querySelector('dialog');
  document.querySelector('#show').onclick = function() {
    dialog.show();
  };
  document.querySelector('#close').onclick = function() {
    dialog.close();
  };
</script>

Check out more sample codes and how it works in detail with a live demo.

There are a few changes applied to the implementation since the last announcement but notable one is:

  • Non-modal <dialog> is no longer vertically centered in the viewport. It has no special positioning behavior beyond its default CSS styling.

If you are curious about further details on the spec update, check out diffs here and here.


Blob support for IndexedDB landed on Chrome Dev

Chrome Dev has landed support for Blob on IndexedDB.

This is a long awaited feature for Chrome that allows IndexedDB API to be able to store and retrieve a Blob without converting it to a Base64 string.

IndexedDB provides large scale key-value type persistent storage that is available on most of modern browsers (Safari apparently will land support in iOS8 and Mac OS X 10.10). Check out its implementation status.

Blob is a file-like binary object modern JavaScript engines can handle. File objects inherits from Blob. You can also fetch images and files as Blob via XMLHttpRequest. Check out its implementation status.

Storing a Blob on IndexedDB

There is no way to feature detect the Blob availability in IndexedDB. You basically have to try-catch then use string instead of Blob if it is not available. Here's some sample code:

// Create an example Blob object
var blob = new Blob(['blob object'], {type: 'text/plain'});

try {
  var store = db.transaction(['entries'], 'readwrite').objectStore('entries');

  // Store the object  
  var req = store.put(blob, 'blob');
  req.onerror = function(e) {
    console.log(e);
  };
  req.onsuccess = function(event) {
    console.log('Successfully stored a blob as Blob.');
  };
} catch (e) {
  var reader = new FileReader();
  reader.onload = function(event) {
    // After exception, you have to start over from getting transaction.
    var store = db.transaction(['entries'], 'readwrite').objectStore('entries');

    // Obtain DataURL string
    var data = event.target.result;
    var req = store.put(data, 'blob');
    req.onerror = function(e) {
      console.log(e);
    };
    req.onsuccess = function(event) {
      console.log('Successfully stored a blob as String.');
    };
  };
  // Convert Blob into DataURL string
  reader.readAsDataURL(blob);
}

Blob support for IndexedDB is already available on Firefox and Internet Explorer as well. Safari support needs to be investigated.

Enjoy!


DevTools Digest - Chrome 35: Updates to the Developer Tools in Chrome 35

Updates to the Chrome Developer Tools: CSS property quick search, memory stats for heap snapshots, CodeMirror upgrade and more.


Data-binding Revolutions with Object.observe()

Learn about Object.observe() - a new feature giving JavaScript the power to directly observe changes to objects.


Debugging Asynchronous JavaScript with Chrome DevTools

Up your JavaScript debugging kung fu with asynchronous call stack traces in the Chrome DevTools.


Build with Chrome: Bringing LEGOŽ bricks to the Multi-Device Web

The Build With Chrome team redesigned the site to support both mouse and touch input.


DevTools Digest: Updates to the Developer tools in Chrome 33

Updates to the Chrome Developer Tools: async call stacks, edit locations, goto :line:column



@2014 CompCoding.com