Skip to content

Instantly share code, notes, and snippets.

@SaxxonPike
Created January 20, 2017 21:53
Show Gist options
  • Select an option

  • Save SaxxonPike/52bfc71bb91dcc0c896d8af64ed7044f to your computer and use it in GitHub Desktop.

Select an option

Save SaxxonPike/52bfc71bb91dcc0c896d8af64ed7044f to your computer and use it in GitHub Desktop.
"Must" promise addin
(function(){
// ---------------------------------------------------------------
// INITIALIZATION
// ---------------------------------------------------------------
// initialize library
var lib = {};
if (window.Must) {
lib = window.Must;
} else {
window.Must = lib;
}
// ---------------------------------------------------------------
// UTILITY
// ---------------------------------------------------------------
// shallow clone object
function clone(obj) {
return merge({}, obj);
}
function curryXHR(method) {
return function(url, options) {
return executeEachXHR(url, merge({ method: method }, options));
};
}
// execute XMLHttpRequest for each file
function executeEachXHR(files, options) {
if (files) {
var promises = [];
var opt;
if (!isArray(files)) {
opt = clone(options);
opt.url = files;
return executeXHR(opt);
} else {
for (var i in files) {
opt = clone(options);
opt.url = files[i];
promises.push(executeXHR(opt));
}
return Promise.all(promises);
}
} else {
return Promise.resolve([]);
}
}
// execute XMLHttpRequest
function executeXHR(options) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
var opt = options ? clone(options) : {};
var method = isolateOption(opt, "method");
var url = isolateOption(opt, "url");
var data = isolateOption(opt, "data");
xhr.open(method, url, true);
merge(xhr, opt);
xhr.onload = function(e) {
if (this.status == 200) {
resolve(this.response);
} else {
reject(Error(e.error));
}
};
xhr.send(data);
});
}
// return whether or not the object is an array
function isArray(v) {
return v.constructor === Array;
}
// get value from hash and remove it if exists
function isolateOption(options, key, defaultValue) {
if (options) {
var result = options[key];
delete options[key];
return result;
}
return defaultValue;
}
// return whether or not the object is a promise
function isPromise(v) {
return v.constructor === Promise;
}
// shallow merge two objects
function merge(target, source) {
source = source || {};
for (var i in source) {
target[i] = source[i];
}
return target;
}
// take a function and wrap it in a promise
function promisify(f, data) {
if (isPromise(f)) {
return f;
} else {
return new Promise(function(resolve, reject) {
try {
var result = f(data);
resolve(result);
} catch(e) {
reject(e);
}
});
}
}
// ---------------------------------------------------------------
// INTERFACE
// ---------------------------------------------------------------
// perform async DELETE operation
lib.delete = function(url, data) {
return curryXHR("DELETE")(url, { data: data });
};
// pass-through
lib.do = function(f, data) {
return promisify(f, data);
}
// because English is fun
lib.first = function(f, data) {
return lib.do(f, data);
}
// perform async GET operation
lib.get = function(url, data) {
return curryXHR("GET")(url, { data: data });
};
// perform async GET operation and convert to JSON
lib.getJson = function(url, data) {
return lib.get(url, data).then(function(result) {
if (isArray(result)) {
return Promise.resolve(result.map(function(o) { JSON.parse(o); }));
} else {
return Promise.resolve(JSON.parse(result));
}
});
};
// perform async PATCH operation
lib.patch = function(url, data) {
return curryXHR("PATCH")(url, { data: data });
};
// perform async POST operation
lib.post = function(url, data) {
return curryXHR("POST")(url, { data: data });
};
})();
@SaxxonPike

Copy link
Copy Markdown
Author

Prerequisites

You will need a browser capable of supporting ES6 promises.
Click here to find out which browsers you can use.

Polyfill

If you need to get support for promises in an older browser (and
chances are you do), check out taylorhakes/promise-polyfill.
It's very small and compliments this library quite well.

Usage

Request a single file

With promises, there are no events to fiddle with.

function showMe(myFile) {
  alert(myFile);
}

Must
  .get('myfile.json')
  .then(showMe);

Request multiple files

The results will be in the same order as the array you passed in
with the file names. Even if some of them finish loading out of
order.

function showMeEverything(myFiles) {
  for (var i in myFiles) {
    alert(myFiles[i]);
  }
}

Must
  .get([
    'myfile1.json',
    'myfile2.json'
  ])
  .then(showMeEverything);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment