Skip to content

Instantly share code, notes, and snippets.

Last active Nov 29, 2016
What would you like to do?
Use ember-concurrency to load the facebook API on demand
/* global FB */
import Ember from 'ember';
import { task } from 'ember-concurrency';
const { RSVP } = Ember;
* Service that lazy loads the Facebook JavaScript SDK, but
* provides a synchronous API
export default Ember.Service.extend({
* Run an arbitrary block of code using the `FB` api once it is
* guaranteed to have been loaded by passing it a callback. Once the
* SDK is known to have been loaded, then the callback will be
* invoked synchronously.
* The callback should be a function accepting a single parameter
* which is the `FB` object serving as the primary namespace of the
* Facebook SDK. E.g.
* => FB.login() );
* or
* => FB.XFMBL.parse(document.body));
* @method run
* @param {Function} - callback to run against API
run(callback) {
return this.get('runTask').perform(callback);
* Ember Concurrency task making sure that operations against the
* SDK run inside the same callstack.
* Normally, when blocking for the SDK to load, you would use a
* promise callback to make sure your code runs in the proper
* order. Unfortunatley, that means losing the calling context to
* the next tick of the Ember run loop.
* This task takes the asynchronous portion (waiting for the
* Facebook SDK to load) and yields to it; continuing with the
* computation once it is ready. In this way the calling context and
* call stack are preserved.
* @private
runTask: task(function * (callback, thisArg = window) {
let sdk = yield this.setupSDK();
return, sdk);
* Inject the Facebook SDK script into the page, and initialize it.
* This injects the script that loads the SDK. Note that contrary to
* the Facebook docs, this script has the `async` flag set to true
* so that it will not block in any way whatsoever. In that way, it
* should be available to scripts as soon as possible
* @private
setupSDK() {
let promise = new RSVP.Promise((resolve, reject)=> {
window.fbAsyncInit = ()=> {
try {
} catch (e) {
// this code is scraped straight from the facebook sdk
// normally it is injected via a script tag, but since we're
// doing it programatically, there is no need.
// for details:
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); = id;
js.src = `//`;
js.async = "true";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
this.setupSDK = ()=> promise;
return promise;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment