Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Friday, August 29, 2014

AngularJS custom scrollbar directive

On a recent project I needed to create a widget that had a similar look and feel across multiple platforms. This widget had a limited size and needed scrolling. When developing on my Macbook the scrollbars were working fine and everything seemed ok. As soon as we started testing it in Windows, the scrollbar width caused an issue with the rendering pushing all the content down.

The solution that we decided on was to use a custom scrollbar. After scouring the web for custom scrollbars in JavaScript I found TinyScrollbar. I liked it because it didn't use jQuery as we were using AngularJS and didn't want to bog down our app with jQuery. I decided to tweak it and port it to AngularJS as a directive.

It's available on github and via bower (bower install ng-tiny-scrollbar) and a demo can be seen here.

Wednesday, July 9, 2014

npm install ENOENT errors

I've been working on a project that is built using NodeJS. Our development environment is a bit of a hybrid. Most of the developers are developing on Macs, with one exception. Our build server is on Windows and our site is running in Windows Azure. For the most part developing NodeJS on a Mac is quite straightforward. All the tooling is readily available and tends to work quite well. Not so much on Windows. So when our build server starting to run into issues installing the requestify package, we chalked it up to something not liking Windows.

We were getting ENOENT errors where npm was complaining that it couldn't find files that it was supposed to download on the file system. Since the error was happening installing a dependency of a dependency, we thought maybe it was a long paths issue. However, we couldn't even get it to install running in the root directory. We decided to use a work around to switch to a different version of that particular dependency.

Weeks later I ran into the same issue, but this time on my Mac. I found a solution by running npm cache clean before running npm install again. I tried it on the Windows build server and it started working again.

TL;DR;
If you're seeing ENOENT errors when running npm install try running npm cache clean and try again.

Monday, October 1, 2012

Node.js, the next web development platform?

Node.js has been gaining steam over the last little while, thanks to videos like this, showing how Node.js can handle 1000 concurrent requests. The development community has grown by leaps and bounds and new packages are constantly being added to NPM. In addition to this, Microsoft has thrown its weight behind it and has provided support for Node.js development in Windows Azure and their WebMatrix IDE. The selling features sound pretty good compared to existing frameworks and architectures:
  • Better memory efficiency under high loads compared to traditional thread based concurrency model
  • No locks and as a result no dead locks
  • HTTP is a first class protocol, this means it's a good foundation for web libraries and frameworks
  • Developers can write code in one language on the client and server
In order to jump right in and start learning Node.js I decided to write an adapter for the jugglingdb ORM. This is an ORM which is bundled in the very Ruby on Rails like framework Railway.js. The adapter was written to integrate into Windows Azure Table Storage and is available in github and on npm.

From this experience I've learned several things, the most important of which is that Node.js is not ready for primetime. While it's great for doing simple endpoints, complex applications seem to be very hard to troubleshoot and debug. This is due to the use of async callbacks all over the place. While this allows high concurrency, debugging becomes a muddled mess. Here is an example of the getTable function in the TableService class, provided by Microsoft.

TableService.prototype.getTable = function (table, optionsOrCallback, callback) {
  var options = null;
  if (typeof optionsOrCallback === 'function' && !callback) {
    callback = optionsOrCallback;
  } else {
    options = optionsOrCallback;
  }

  validateTableName(table);
  validateCallback(callback);

  var webResource = WebResource.get("Tables('" + table + "')");
  webResource.addOptionalHeader(HeaderConstants.CONTENT_TYPE, 'application/atom+xml;charset="utf-8"');
  webResource.addOptionalHeader(HeaderConstants.CONTENT_LENGTH, 0);

  var processResponseCallback = function (responseObject, next) {
    responseObject.tableResponse = null;
    if (!responseObject.error) {
      responseObject.tableResponse = TableResult.parse(responseObject.response.body);
    }

    var finalCallback = function (returnObject) {
      callback(returnObject.error, returnObject.tableResponse, returnObject.response);
    };

    next(responseObject, finalCallback);
  };

  this._performRequestExtended(webResource, null, options, processResponseCallback);
};

Not only is this hard to read, it's not clear why all of these layers of callbacks are even necessary. This could just be this one library, however, it also seems that Node.js is solving a problem that isn't there for a vast majority of people. The Railways.js and Express frameworks are great, however, if the problem you are trying to solve is concurrency, you are unlikely to use a heavyweight framework. You are much more likely to build a highly specialized and tuned end point, using low level platform constructs.

That is not to say that it's a lost cause. Projects like TypeScript are seeking to make Node.js development much more scalable. Tools like Jetbrains WebStorm with the Node.js plugin, provide a slew of  functionality for JavaScript development that you may be used to in other development environments. This includes refactoring, code completion, a nodeunit test runner, and debugging

Would I use Node.js on my next project? Potentially for small endpoints that may need high concurrency and throughput. However, I am interested in seeing where the development community takes the concept of JavaScript on the server. Perhaps at some point this will become a viable alternative to the existing platforms and frameworks.

Monday, February 7, 2011

JavaScript/jQuery code optimization (or famous IE bottlenecks)

After we pulled out the Infragistics grid in favor of Telerik MVC Extensions, We've had to code several features, that were available in Infragistics out of the box, ourselves. This was partly due to our data structure not being fully supported by the Telerik grid. That's a topic for another blog post though. One of the features was the ability to select several cells and do spreadsheet like functionality, such as copy/paste and fill. We were mostly testing this out in Chrome/Firefox and with small tables. However, as typically happens, after releasing into our demo environment, our BA told us that the performance was brutal.

Surprise, surprise, it turned out that our grid page ran very slowly in IE(7) with very large tables (50 rows by 35 columns). I wound up being able to trace the bottle neck down to this chunk of code.
$('tbody td', $(this.element)).each(function() {
 if (this.parentElement.rowIndex >= selection.startRowIndex && 
 this.parentElement.rowIndex <= selection.endRowIndex &&
 this.cellIndex >= selection.startColIndex && 
 this.cellIndex <= selection.endColIndex) {
  if (columns[this.cellIndex].readonly != true) {
   $(this).addClass('selected');
  }
 }
});
This is the code for when a user has a cell selected and is either dragging the mouse or holding shift and clicking to select a block of cells. What's happening here is that we're going through all cells in the table body and seeing if it is between the first selected cell and the cell located at the mouse position. I.E. whether or not the cell is in a 'box'. The problem is that we're going through every cell in the table body, even if only one has been selected.

The first optimization was to only go through the rows/columns that were in the selected box, so to speak. This was done using the jQuery slice method. The code is below

$('tbody tr', this.element)
 .slice(selection.startRowIndex, selection.endRowIndex + 1)
 .each(function() {
  $(this).children('td')
   .slice(selection.startColIndex, selection.endColIndex + 1)
   .each(function() {
    if (!columns[this.cellIndex].readonly) {
     $(this).addClass('selected');
    }
   });
 });

The performance improved a lot when the selection box was small, but if the user selected anything bigger than a 4 row by 10 column box the script crawled again. Each row would take approximately 190 ms to run in IE7. So if the user selected 10 rows it would take almost 2 seconds to run. The problem seemed to be the readonly check. If it was taken out, the timing dropped to a fraction of a millisecond.

The problem is that Internet Explorer is very slow processing conditional statements. Doing some unscientific tests on this site I got around the following numbers:

BrowserAverage Time
Chrome 80.02 ms
Firefox 4 b100.66 ms
Internet Explorer 852 ms
Internet Explorer 794 ms

So we had to find a way to optimize that conditional statement. I finally found a jQuery call that seemed to do the trick.

$('tbody tr', this.element)
 .slice(selection.startRowIndex, selection.endRowIndex + 1)
 .each(function() {
  $(this).children('td')
   .slice(selection.startColIndex, selection.endColIndex + 1)
   .not(function() {
    return columns[this.cellIndex].readonly;
   })
   .addClass('selected');
   });

After going through the jQuery code, I'm still not 100% sure why the performance is better with the last statement. A couple of things I've noticed is that using each to do a check on every item seems to be slightly more expensive than not (or for that matter filter). Since each also does a check to make sure the callback hasn't returned false. Also addClass has a lot of overhead so it's quite inefficient to run it on elements one by one. Not sure if that's necessarily the problem either though because the 2nd code snippet ran very quickly when the readonly check was taken out.

If anyone has any ideas on why they think the 3d code snippet runs much faster than the 2nd one I would love to hear it. Until then this just another example of why it's important to optimize your jQuery code.

Thursday, January 27, 2011

Debugging JavaScript

The tools available to web developers have grown a lot in the last 5 years. Time was, the only way to debug JavaScript was to pepper your code with alert statements. Now you can get a variety of plugins and tools that allow you to examine HTML, CSS, JavaScript, and other elements of a web page. Here are some of the better tools out there:

Firebug
One of the best debugging tools out there. Allows you to inspect and modify html elements and style. Comes with a great JavaScript debugger and allows you to examine network usage. Available as an add on for Firefox. (Note if you're using Firefox 4.0 beta make sure you are using version 1.7 of firebug and Firefox 4.0 beta 10 as previous versions are broken)
Internet Explorer Developer Toolbar
Let's face it, if you've developed any kind of web applications, you've grown to despise IE. With its quirks and non standard implementation of all things html, css, and JavaScript , IE is one of the biggest pain points for any web developer. The internet explorer developer toolbar tries to ease some of that pain by providing the ability to examine html and make modifications to style
Visual Studio
A decent tool for debugging JavaScript in IE. Can be a bit of a pain, but contains everything a debugger should: call stack, breakpoints, watch variables, and quick watch.
Chrome Developer Tools
One of the easiest browsers to develop for, also comes with a great set of developer tools. View and change html elements, trace styles, debug JavaScript like a pro, examine loaded resources including XHR content. It also provides optimization and performance analysis

All of these tools are great, but what prompted me to write this blog entry is another great tool out there, JSFiddle. If you've ever tried debugging a small JS problem you know it's a real pain to constantly update your code, reload the page and step through a multitude of lines that your page might contain. JSFiddle provides a great way to isolate problem code and debug it. JSFiddle allows you to enter your HTML, CSS, and JavaScript then run it all in one page. It also allows you to easily load different versions of most of the common OSS JS frameworks that exist. Not only that, but it also provides versioning of your "fiddles". If you haven't signed up for an account I highly recommend it. You don't need an account to use the site, but if you want to save and share your fiddles you will need to have an account.