I've came across this situation a few times before and always found a tricky way to make it work but I'd like to know if there's a best practice for that:
Sometimes you have to use several JavaScript SDKs on a page example: Google jsapi and jQuery.
Google calls this function when the SDK is ready to be used:
google.setOnLoadCallback(MyFunction);
jQuery does everything in this callback:
document.ready();
What if I want to manipulate the dom using jQuery AFTER Google's callback.
What's the best way to tell the browser: "Wait for jQuery AND Google to be ready and do the stuff..."
Is it best to have the jQuery callback nested inside Google callback? Or the other way round? I'm a bit confused.
You can do this in different ways, one of which is to use a global variable;
var googleLoaded = false;
google.setOnLoadCallback(function(){
googleLoaded = true;
mainCallback();
});
document.ready(mainCallback);
function mainCallback(){
if(googleLoaded){
...
...
}
}
As a general solution, you can do as given below
var jsLibsToLoad = 5;
jsLib1.onLoad(mainCallback);
jsLib2.onLoad(mainCallback);
jsLib3.onLoad(mainCallback);
jsLib4.onLoad(mainCallback);
jsLib5.onLoad(mainCallback);
function mainCallback(){
if(!(--jsLibsToLoad)){
...
...
}
}
I would recommend you to use some AMD tool like RequireJS. RequireJS is a JavaScript file and module loader, and it is really good with dependancy management. In your particular case (using of some traditional/legacy "browser globals" scripts) you should additionally use Shim Config.
At the start using AMD is a little bit tricky, but it gave a great benefits when you get used to it. It will improve the speed and quality of your code.
Related
I'm using React-Intl with webpack and I need the Intl shim to support Safari and IE, but I don't want to load it for browsers that already support the Intl spec.
The polyfill is pretty huge (900kb), how can I ensure it only gets loaded in browsers that don't support it already?
There are a few things that you need to do.
Make sure to require intl/Intl which loads the core library and not all of the associated countries. This will reduce the size of the library from from around 900kb to around 150kb.
Use webpack's require.ensure or require([]) functions to dynamically require Intl.js only when needed. This will create a separate bundle for just the Intl.js file, which will be loaded on an as-needed basis.
lib/shim.js
// shim for Intl needs to be loaded dynamically
// so we callback when we're done to represent
// some kind of "shimReady" event
module.exports = function(callback) {
if (!window.Intl) {
require(['intl/Intl'], function(Intl) {
window.Intl = Intl;
callback();
});
} else {
setTimeout(callback, 0); // force async
}
};
app.js
var shimReady = require('lib/shim');
shimReady(startApp);
Note: You may also need access to country-specific information and properties. For my basic needs I didn't actually require this data, but if you do be sure to read the section on Intl.js website loading locale data.
An simple (non-webpack) approach would be to do something like this in your HTML:
<script>
if (!window.Intl) { document.write('<script src="/js/Intl.min.js"><\/script>'); }
</script>
Though document.write is not considered a best practice, this would provide a blocking approach to solving the problem, resulting in considerably less code in your the application. This solution does not use webpack, but may be a suitable solution for many people in this situation.
Looking for requirejs.noConflict(), or some way to remove the global footprint from the library. My use case is that I'm writing a widget to run in a 3rd party page which might already define require and define (with a previous version of requirejs or even another library entirely).
I've tried implementing this myself and it mostly works. For simplicity lets assume I do not restore original values, only remove the footprint. I do something like this in my data-main:
var mycontext = requirejs.config({context : 'asdf', baseUrl : 'http://foo.com' });
mycontext(['require','foo'], function (require, foo) {
var f = require('foo');
});
// namespace cleanup
window.requirejs = undefined;
window.require = undefined;
window.define = undefined;
The problem here is that the f value from require('foo') returns null, but only iff I do my namespace cleanup. This smells like a bug in requirejs, but I'm hoping there's an official no-conflict solution.
Hard to google this one due to all the jQuery related noConflict() questions.
The RequireJS documentation has a section on this titled "HOW CAN I PROVIDE A LIBRARY TO OTHERS THAT DOES NOT DEPEND ON REQUIREJS?"
You can also have a look at the example build file, which shows how wrap can be used.
A good example of how this works is the Flight library.
By default the library uses AMD but there is a standalone version that wraps all the modules in an anonymous function and includes a tiny require/define API at the top (They use their own build tool for this). Source can be found here.
Note that for this to work all the modules will require IDs, but the r.js optimiser will handle that for you.
Using these techniques should allow you to leave any already defined require/define variables alone.
Let me know how it works internally require () function in javascript.
I want to make something like this: define(["./path"], function(cart, inventory) { });,
but every time I look for it on Google, the results are only frameworks or tutorials for use it, but I wonder how it works inside this function, make it just to understand it better.
Does anyone know of a tutorial that explains how to do this function manually?
Thank you very much.
require function it's just a part of commonjs standart. This standart has a number of implementations for working in browser (requirejs, stitch).
See https://github.com/medikoo/modules-webmake and JavaScript Modules slides: http://www.slideshare.net/medikoo/javascript-modules-done-right It's all explained there.
"define" is AMD require, which is totally different beast from CommonJS/NodeJS require, I would suggest to just stick to CommonJS/Node.js style, it's simpler, more powerful and your code would be cleaner.
First of all I am new to javascript so this question might be stupid.
I have a requirement where i would provide a js script to other websites to include in their webpages.
Now my question is should I use jquery or plain javascript.Will/Can jquery effect the rest of the functionality of the site.
Plus what is the benefit I will get using jquery over plain javascript.
My requirement is to get all images of the website and do some processing on the images on these websites.
Thanks in Advance.
I would say, if the processing does not involve jQuery then do not use it.
You need to deal with the following issues if you include it
failure to load (for network reasons)
conflict with other versions locally loaded
conflict with other libraries locally loaded
All issues have workarounds/solutions but you have to implement each an everyone of those.
If you just need to find all images in page, then you can use the .getElementsByTagName() method
var imagelist = document.getElementsByTagName('img');
and just do the processing on that..
You might need of-course to attach your code at the load event to be sure that whatever your code does, the DOM is ready to accept it..
for modern browsers that would be .addEventListener(), while for IE it would be .attchEvent()
your script could be something like this
(function(){ // wrap in a self-invoking function to avoid global name-space pollution
// attach to the load event so out code runs once the page has loaded
if (window.addEventListener) { // modern
window.addEventListener('load', imageProcessor, false);
}
else if (window.attachEvent) { // IE
window.attachEvent('onload', imageProcessor );
}
function imageProcessor(){
// get all images
var imagelist = document.getElementsByTagName('img');
// loop the list of images to do something with each image
for (var img = 0; img < imagelist.length; img++)
{
var currentImage = imagelist[img];
// do processing on the currentImage which hold a reference to the image
}
}
})(); // do the self-invoking
demo: http://jsfiddle.net/gaby/nXPzk/
this would be much more easier to achieve with jQuery, mostly because you want to be able to distribute your script to any browser(and jQuery is a cross-browser library), but it does have it's downsides.
If it's your own project, your own page, you know exactly what and when to load/execute, but if you're giving your script to other folks, you have to think of 3 problems at least:
different libraries conflicts
This can be resolved using jquery's noConflict method, but I've seen it fail in some circumstances
same library conflicts
Say that the user already has loaded version X of jQuery. You oblige him to load version Y too, and besides the fact that this would be very inefficient, it may cause conflicts between different jQuery versions.
There are workarounds for this( to check if jQuery exists and load it asynchroniously if it doesn't) but the code gets a bit more complicated.
code size
When i think of a third party piece of code, I'm thinking...hmm a few kb to load to be able to run a function, but if you want to use jQuery, you may be forcing the one who uses your script to load a whole library just for your one functionality instead of a 1-2 kb (needles to say what the implications are if the user has a slow connection)
Having both the ups and downs in mind, it really depends on what are you doing, so, as Gaby aka G. Petrioli said, " if the processing does not involve jQuery then do not use it".
JQuery is much more convenient than plain javascript. You don't have to worry about cross-browser compatibility (e.g. IE vs. Firefox vs. Chrome). I would recommend this over javascript unless you are want to handle that yourself :)
You can load in the Jquery library, but that might be a little heavy than what you're looking for. Also, you will need to fetch the library from a server, which adds another point of failure (however, if you host this on your own server, then you will have more control).
TLDR: JQuery is convenient. If you have access to it, then you should use it.
Don't be afraid to use any technical jargon or low-level explanations for things, please. I'm savvy enough with computer architecture and low-level programming languages to comprehend any optimizations or memory management techniques, as well as complex structures (classes, member variables, etc.)
My primary focus of code is web-based applications. I work with PHP a lot and I've been learning CSS quickly. Javascript is currently my bottleneck, however. I know enough Javascript to do just about anything sans frameworks (DOM manipulation, AJAX queries, etc.). I also know that I can make my code run quicker, optimize it for specific cases, and I can shrink the over-all size of my code (no external script to include) by manually coding everything. However for ease of reading by other programmers and for speed of coding I'm trying to learn at least one Javascript framework.
After reading through the documentation on a number of frameworks and looking at some tutorials, I preferred jQuery. It allowed for very powerful iterative code in a single line and it had a very small chance of global variable namespace collision. From what I could tell, the ONLY global variable declared is the $ variable and everything else happens within this namespace, and there were even ways to access the namespace without this variable if you wanted to have two frameworks side-by-side. It also had a very small file to include (24 kilobytes gzipped) which means less server load.
My question is what are good practices in creating a jQuery plugin? If I were to start coding websites in jQuery, how should I go about it for the best interoperability and design? I want to ensure that my code can run along-side any other jQuery without interference, it's possible to build plugins off of my code, and I minimize use of the jQuery namespace so that I don't steal variables that might be used by another script.
Read the jQuery plugin authoring suggestions, also look at the unminified jQuery. Notice the last line: window.jQuery = window.$ = jQuery; So there are two global variables window.jQuery and window.$. To delve into this issue a little deeper, read more about the documentation on using jQuery with other libraries and jQuery.noConflict():
// Trigger no conflict mode.
$.noConflict();
// Code that uses other library's $ can follow here.
For writing plugins, make sure to pay special attention to the section called Maintaining Chainability (since jQuery makes use of chainability so nicely). You have to explicitly return this in your plugins to maintain chainability. Additionally, speaking of clashing with other variables, make sure you stop your plugin from clashing with other code by using a closure:
// Use a closure so you can use the dollar sign in your plugin,
// but you don't clash with other uses of the dollar sign in the script
// around where you define your plugin (other libraries, etc.)
(function( $ ){
// Adding your plugin to jQuery
$.fn.yourPlugin = function() {
// Maintain chainability
return this.each(function() {
// ...
});
};
}( jQuery ));
There's a lot of other great information on that plugin authoring page. The above is just the bare bones. There's info on defaults and options, namespacing, and many other things.
Also, if you're concerned about your variables clashing, you can also make use of closures for you own "regular" code... not just jQuery plugins. To do this, enclose your script in a self invoking anonymous function:
(function() {
var ... // these vars will not clash with
// anything outside this anonymous function
// You can do your jQuery in here if you need to access
// the local vars:
$(function() { ... });
}());
For example:
// global 'clash'
var clash = "test";
(function() {
// local 'clash'
var clash = "something else";
// this 'clash' shadows but doesn't change the global 'clash'
}());
alert(clash);
// The global 'clash' has stayed unaffected by the local `clash`
// Output: test
jsFiddle example
You can add plugin methods without using the extend method:
jQuery.fn.myPlugin = function(opts) { ... }
You can use the extend: if you're just looking to extend the jQuery object with multiple
functions you would do:
jQuery.extend({
funcName: function(){
//function code
},
funcName2: function(){
//function code
}
});
"jQuery.extend adds a set of properties to the jQuery object.
jQuery.fn.extend adds a set of properties to the jQuery.fn object
(which is then accessibly via $().foo)."
jQuery.fn is a shortcut for jQuery.prototype.
The official documentation on plugins: http://docs.jquery.com/Plugins/Authoring
Mike Alsup has this good tutorial/pattern discussion:http://www.learningjquery.com/2007/10/a-plugin-development-pattern
EDIT: One other note, be careful of your names with use of packers/minimizers - test on the one of your choice in this regard.