使用fetch遇到过的坑

时间:2022-08-18 21:22:30

前段时间在项目中用到了这个fetch 来代替Ajax 进行网络请求。也踩了不少的坑,在这边列举出来以及他的解决方法。


1.如何保持每次请求的会话一致?

  在用fetch进行网络请求的时候,发现每次请求到服务端的时候,他的sessionId 都是不一样的,后面排查原来是在请求的时候fetch默认是不会带上本地jsessionId,以至于服务端无法接收到,所以会重新创建一个新的session。


 解决办法:

 

var init = {
credentials: 'include' // 请求带上cookies,是每次请求保持会话一直
...
}

2.兼容性,支持IE10+、谷歌、火狐等

   由于fetch是一个新技术,有些旧的浏览器对它并不支持,这时候要怎么兼容?

 

   解决办法:

   引入一个额外的补丁es6-promise.js可以使它很好的支持IE9以上的版本,那IE8呢?IE8 需要改fetch.js源码才能支持

   fetch.js 只需改两处:

  使用fetch遇到过的坑

使用fetch遇到过的坑


  try里面的是源码本身的,catch里面的是小编额外加的。细心的会发现这两处改的是一样的,都是对getOwnPropertyNames进行替换。但是IE8也不支持forEach为啥没有替换    呢? 其实有替换了,只是不再这边体现。我把它写进了Array.prototype里面了,其实fetch.js里面也用到了indexOf,它在IE8下也是不支持,我把它一并的放在Array.prototype

 代码如下:

Array.prototype.forEach = function(callback, thisArg) {  
var T, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
var O = Object(this);
var len = O.length >>> 0; // Hack to convert O.length to a UInt32
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
if (thisArg) {
T = thisArg;
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
};

最后附上修改后的文件以及自己封装的一个网络请求request.js。

request.js:

/**
* 该方法仅支持IE8以上
* 网络请求方法
* url:请求地址
* options = {
* catchs: 异常处理,控制台抛出的异常是否自己处理:true 是,false 否 由公共方法统一处理优化显示给用户 默认 false
* credentials: 请求带上cookies,是每次请求保持会话一直
* method: 请求使用的方法,如 GET、POST
* headers: 请求的头信息,形式为 Headers 对象或 ByteString。
* body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
* mode: 请求的模式,如 cors、no-cors 或者same-origin。是否允许跨域请求
* cache: 请求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.
* }
*/

var $requst = function (url, options) {
var myHeaders = {
'Content-Type': 'text/html; charset=utf-8'
};
var init = {
credentials: 'include',
method: (options && options.method) || 'GET',
headers: (options && options.headers) || myHeaders,
cache: (options && options.cache) || 'default'
}
if (options && options.body) {
init.body = JSON.stringify(options.body)
}
return fetch(url, init)
.then(function(response) {
if (response.ok) {
return _returnContentByType(response);
} else {
if (options && options.catchs) {
throw new Error(response.statusText);
} else {
var error = new Error(response.statusText);
throw new Error('');
}
}
});
};

/**
* 根据type返回不同格式的response
*/
var _returnContentByType = function (response) {
var type = response.headers.get('Content-Type').split(";")[0];
switch (type) {
case 'text/html':
return response.text();
break
case 'application/json':
return response.json();
break
default:
}
};

fetch.js:

(function() {
'use strict';

// if __disableNativeFetch is set to true, the it will always polyfill fetch
// with Ajax.
if (!self.__disableNativeFetch && self.fetch) {
return
}

function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name)
}
if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
throw new TypeError('Invalid character in header field name')
}
return name.toLowerCase()
}

function normalizeValue(value) {
if (typeof value !== 'string') {
value = String(value)
}
return value
}

function Headers(headers) {
this.map = {}

if (headers instanceof Headers) {
headers.forEach(function(value, name) {
this.append(name, value)
}, this)

} else if (headers) {
try{
Object.getOwnPropertyNames(headers).forEach(function(name) {
this.append(name, headers[name])
}, this)
}catch(e){
var a = [];
for (var i in headers) {
if (headers.hasOwnProperty(i)) {
a.push(i); // 输出 foo asj
}
};
a.forEach(function(name) {
this.append(name, headers[name])
}, this)
}
}
}

Headers.prototype.append = function(name, value) {
name = normalizeName(name)
value = normalizeValue(value)
var list = this.map[name]
if (!list) {
list = []
this.map[name] = list
}
list.push(value)
}

Headers.prototype['delete'] = function(name) {
delete this.map[normalizeName(name)]
}

Headers.prototype.get = function(name) {
var values = this.map[normalizeName(name)]
return values ? values[0] : null
}

Headers.prototype.getAll = function(name) {
return this.map[normalizeName(name)] || []
}

Headers.prototype.has = function(name) {
return this.map.hasOwnProperty(normalizeName(name))
}

Headers.prototype.set = function(name, value) {
this.map[normalizeName(name)] = [normalizeValue(value)]
}

Headers.prototype.forEach = function(callback, thisArg) {
try{
Object.getOwnPropertyNames(this.map).forEach(function(name) {
this.map[name].forEach(function(value) {
callback.call(thisArg, value, name, this)
}, this)
}, this)
}catch(e){
var a = [];
for (var i in this.map) {
if (this.map.hasOwnProperty(i)) {
a.push(i); // 输出 foo asj
}
};
a.forEach(function(name) {
this.map[name].forEach(function(value) {
callback.call(thisArg, value, name, this)
}, this)
}, this)
}
}

function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true
}

function fileReaderReady(reader) {
return new Promise(function(resolve, reject) {
reader.onload = function() {
resolve(reader.result)
}
reader.onerror = function() {
reject(reader.error)
}
})
}

function readBlobAsArrayBuffer(blob) {
var reader = new FileReader()
reader.readAsArrayBuffer(blob)
return fileReaderReady(reader)
}

function readBlobAsText(blob, options) {
var reader = new FileReader()
var contentType = options.headers.map['content-type'] ? options.headers.map['content-type'].toString() : ''
var regex = /charset\=[0-9a-zA-Z\-\_]*;?/
var _charset = blob.type.match(regex) || contentType.match(regex)
var args = [blob]

if(_charset) {
args.push(_charset[0].replace(/^charset\=/, '').replace(/;$/, ''))
}

reader.readAsText.apply(reader, args)
return fileReaderReady(reader)
}

var support = {
blob: 'FileReader' in self && 'Blob' in self && (function() {
try {
new Blob();
return true
} catch(e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
}

function Body() {
this.bodyUsed = false


this._initBody = function(body, options) {
this._bodyInit = body
if (typeof body === 'string') {
this._bodyText = body
} else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
this._bodyBlob = body
this._options = options
} else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
this._bodyFormData = body
} else if (!body) {
this._bodyText = ''
} else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) {
// Only support ArrayBuffers for POST method.
// Receiving ArrayBuffers happens via Blobs, instead.
} else {
throw new Error('unsupported BodyInit type')
}
}

if (support.blob) {
this.blob = function() {
var rejected = consumed(this)
if (rejected) {
return rejected
}

if (this._bodyBlob) {
return Promise.resolve(this._bodyBlob)
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as blob')
} else {
return Promise.resolve(new Blob([this._bodyText]))
}
}

this.arrayBuffer = function() {
return this.blob().then(readBlobAsArrayBuffer)
}

this.text = function() {
var rejected = consumed(this)
if (rejected) {
return rejected
}

if (this._bodyBlob) {
return readBlobAsText(this._bodyBlob, this._options)
} else if (this._bodyFormData) {
throw new Error('could not read FormData body as text')
} else {
return Promise.resolve(this._bodyText)
}
}
} else {
this.text = function() {
var rejected = consumed(this)
return rejected ? rejected : Promise.resolve(this._bodyText)
}
}

if (support.formData) {
this.formData = function() {
return this.text().then(decode)
}
}

this.json = function() {
return this.text().then(JSON.parse)
}

return this
}

// HTTP methods whose capitalization should be normalized
var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']

function normalizeMethod(method) {
var upcased = method.toUpperCase()
return (methods.indexOf(upcased) > -1) ? upcased : method
}

function Request(input, options) {
options = options || {}
var body = options.body
if (Request.prototype.isPrototypeOf(input)) {
if (input.bodyUsed) {
throw new TypeError('Already read')
}
this.url = input.url
this.credentials = input.credentials
if (!options.headers) {
this.headers = new Headers(input.headers)
}
this.method = input.method
this.mode = input.mode
if (!body) {
body = input._bodyInit
input.bodyUsed = true
}
} else {
this.url = input
}

this.credentials = options.credentials || this.credentials || 'omit'
if (options.headers || !this.headers) {
this.headers = new Headers(options.headers)
}
this.method = normalizeMethod(options.method || this.method || 'GET')
this.mode = options.mode || this.mode || null
this.referrer = null

if ((this.method === 'GET' || this.method === 'HEAD') && body) {
throw new TypeError('Body not allowed for GET or HEAD requests')
}
this._initBody(body, options)
}

Request.prototype.clone = function() {
return new Request(this)
}

function decode(body) {
var form = new FormData()
body.trim().split('&').forEach(function(bytes) {
if (bytes) {
var split = bytes.split('=')
var name = split.shift().replace(/\+/g, ' ')
var value = split.join('=').replace(/\+/g, ' ')
form.append(decodeURIComponent(name), decodeURIComponent(value))
}
})
return form
}

function headers(xhr) {
var head = new Headers()
var pairs = xhr.getAllResponseHeaders().trim().split('\n')
pairs.forEach(function(header) {
var split = header.trim().split(':')
var key = split.shift().trim()
var value = split.join(':').trim()
head.append(key, value)
})
return head
}

Body.call(Request.prototype)

function Response(bodyInit, options) {
if (!options) {
options = {}
}

this._initBody(bodyInit, options)
this.type = 'default'
this.status = options.status
this.ok = this.status >= 200 && this.status < 300
this.statusText = options.statusText
this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
this.url = options.url || ''
}

Body.call(Response.prototype)

Response.prototype.clone = function() {
return new Response(this._bodyInit, {
status: this.status,
statusText: this.statusText,
headers: new Headers(this.headers),
url: this.url
})
}

Response.error = function() {
var response = new Response(null, {status: 0, statusText: ''})
response.type = 'error'
return response
}

var redirectStatuses = [301, 302, 303, 307, 308]

Response.redirect = function(url, status) {
if (redirectStatuses.indexOf(status) === -1) {
throw new RangeError('Invalid status code')
}

return new Response(null, {status: status, headers: {location: url}})
}

self.Headers = Headers;
self.Request = Request;
self.Response = Response;

self.fetch = function(input, init) {
return new Promise(function(resolve, reject) {
var request
if (Request.prototype.isPrototypeOf(input) && !init) {
request = input
} else {
request = new Request(input, init)
}

var xhr = new XMLHttpRequest()

function responseURL() {
if ('responseURL' in xhr) {
return xhr.responseURL
}

// Avoid security warnings on getResponseHeader when not allowed by CORS
if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) {
return xhr.getResponseHeader('X-Request-URL')
}

return;
}

var __onLoadHandled = false;

function onload() {
if (xhr.readyState !== 4) {
return
}
var status = (xhr.status === 1223) ? 204 : xhr.status
if (status < 100 || status > 599) {
if (__onLoadHandled) { return; } else { __onLoadHandled = true; }
reject(new TypeError('Network request failed'))
return
}
var options = {
status: status,
statusText: xhr.statusText,
headers: headers(xhr),
url: responseURL()
}
var body = 'response' in xhr ? xhr.response : xhr.responseText;

if (__onLoadHandled) { return; } else { __onLoadHandled = true; }
resolve(new Response(body, options))
}
xhr.onreadystatechange = onload;
xhr.onload = onload;
xhr.onerror = function() {
if (__onLoadHandled) { return; } else { __onLoadHandled = true; }
reject(new TypeError('Network request failed'))
}

xhr.open(request.method, request.url, true)

// `withCredentials` should be setted after calling `.open` in IE10
// http://*.com/a/19667959/1219343
try {
if (request.credentials === 'include') {
if ('withCredentials' in xhr) {
xhr.withCredentials = true;
} else {
console && console.warn && console.warn('withCredentials is not supported, you can ignore this warning');
}
}
} catch (e) {
console && console.warn && console.warn('set withCredentials error:' + e);
}

if ('responseType' in xhr && support.blob) {
xhr.responseType = 'blob'
}

request.headers.forEach(function(value, name) {
xhr.setRequestHeader(name, value)
})

xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
})
}
self.fetch.polyfill = true

// Support CommonJS
if (typeof module !== 'undefined' && module.exports) {
module.exports = self.fetch;
}
})();

es6-promise.js:
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
* @version 3.2.2+39aa2571
*/

(function() {
"use strict";
function lib$es6$promise$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}

function lib$es6$promise$utils$$isFunction(x) {
return typeof x === 'function';
}

function lib$es6$promise$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}

var lib$es6$promise$utils$$_isArray;
if (!Array.isArray) {
lib$es6$promise$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
lib$es6$promise$utils$$_isArray = Array.isArray;
}

var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray;
var lib$es6$promise$asap$$len = 0;
var lib$es6$promise$asap$$vertxNext;
var lib$es6$promise$asap$$customSchedulerFn;

var lib$es6$promise$asap$$asap = function asap(callback, arg) {
lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback;
lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg;
lib$es6$promise$asap$$len += 2;
if (lib$es6$promise$asap$$len === 2) {
// If len is 2, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
if (lib$es6$promise$asap$$customSchedulerFn) {
lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush);
} else {
lib$es6$promise$asap$$scheduleFlush();
}
}
}

function lib$es6$promise$asap$$setScheduler(scheduleFn) {
lib$es6$promise$asap$$customSchedulerFn = scheduleFn;
}

function lib$es6$promise$asap$$setAsap(asapFn) {
lib$es6$promise$asap$$asap = asapFn;
}

var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {};
var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;
var lib$es6$promise$asap$$isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';

// test for web worker but not in IE10
var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';

// node
function lib$es6$promise$asap$$useNextTick() {
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
// see https://github.com/cujojs/when/issues/410 for details
return function() {
process.nextTick(lib$es6$promise$asap$$flush);
};
}

// vertx
function lib$es6$promise$asap$$useVertxTimer() {
return function() {
lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush);
};
}

function lib$es6$promise$asap$$useMutationObserver() {
var iterations = 0;
var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });

return function() {
node.data = (iterations = ++iterations % 2);
};
}

// web worker
function lib$es6$promise$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = lib$es6$promise$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}

function lib$es6$promise$asap$$useSetTimeout() {
return function() {
setTimeout(lib$es6$promise$asap$$flush, 1);
};
}

var lib$es6$promise$asap$$queue = new Array(1000);
function lib$es6$promise$asap$$flush() {
for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) {
var callback = lib$es6$promise$asap$$queue[i];
var arg = lib$es6$promise$asap$$queue[i+1];

callback(arg);

lib$es6$promise$asap$$queue[i] = undefined;
lib$es6$promise$asap$$queue[i+1] = undefined;
}

lib$es6$promise$asap$$len = 0;
}

function lib$es6$promise$asap$$attemptVertx() {
try {
var r = require;
var vertx = r('vertx');
lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
return lib$es6$promise$asap$$useVertxTimer();
} catch(e) {
return lib$es6$promise$asap$$useSetTimeout();
}
}

var lib$es6$promise$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (lib$es6$promise$asap$$isNode) {
lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick();
} else if (lib$es6$promise$asap$$BrowserMutationObserver) {
lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver();
} else if (lib$es6$promise$asap$$isWorker) {
lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel();
} else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') {
lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertx();
} else {
lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout();
}
function lib$es6$promise$then$$then(onFulfillment, onRejection) {
var parent = this;

var child = new this.constructor(lib$es6$promise$$internal$$noop);

if (child[lib$es6$promise$$internal$$PROMISE_ID] === undefined) {
lib$es6$promise$$internal$$makePromise(child);
}

var state = parent._state;

if (state) {
var callback = arguments[state - 1];
lib$es6$promise$asap$$asap(function(){
lib$es6$promise$$internal$$invokeCallback(state, child, callback, parent._result);
});
} else {
lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}

return child;
}
var lib$es6$promise$then$$default = lib$es6$promise$then$$then;
function lib$es6$promise$promise$resolve$$resolve(object) {
/*jshint validthis:true */
var Constructor = this;

if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}

var promise = new Constructor(lib$es6$promise$$internal$$noop);
lib$es6$promise$$internal$$resolve(promise, object);
return promise;
}
var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve;
var lib$es6$promise$$internal$$PROMISE_ID = Math.random().toString(36).substring(16);

function lib$es6$promise$$internal$$noop() {}

var lib$es6$promise$$internal$$PENDING = void 0;
var lib$es6$promise$$internal$$FULFILLED = 1;
var lib$es6$promise$$internal$$REJECTED = 2;

var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject();

function lib$es6$promise$$internal$$selfFulfillment() {
return new TypeError("You cannot resolve a promise with itself");
}

function lib$es6$promise$$internal$$cannotReturnOwn() {
return new TypeError('A promises callback cannot return that same promise.');
}

function lib$es6$promise$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
lib$es6$promise$$internal$$GET_THEN_ERROR.error = error;
return lib$es6$promise$$internal$$GET_THEN_ERROR;
}
}

function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}

function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) {
lib$es6$promise$asap$$asap(function(promise) {
var sealed = false;
var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
lib$es6$promise$$internal$$resolve(promise, value);
} else {
lib$es6$promise$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;

lib$es6$promise$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));

if (!sealed && error) {
sealed = true;
lib$es6$promise$$internal$$reject(promise, error);
}
}, promise);
}

function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === lib$es6$promise$$internal$$FULFILLED) {
lib$es6$promise$$internal$$fulfill(promise, thenable._result);
} else if (thenable._state === lib$es6$promise$$internal$$REJECTED) {
lib$es6$promise$$internal$$reject(promise, thenable._result);
} else {
lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) {
lib$es6$promise$$internal$$resolve(promise, value);
}, function(reason) {
lib$es6$promise$$internal$$reject(promise, reason);
});
}
}

function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable, then) {
if (maybeThenable.constructor === promise.constructor &&
then === lib$es6$promise$then$$default &&
constructor.resolve === lib$es6$promise$promise$resolve$$default) {
lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) {
lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
} else if (lib$es6$promise$utils$$isFunction(then)) {
lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
lib$es6$promise$$internal$$fulfill(promise, maybeThenable);
}
}
}

function lib$es6$promise$$internal$$resolve(promise, value) {
if (promise === value) {
lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFulfillment());
} else if (lib$es6$promise$utils$$objectOrFunction(value)) {
lib$es6$promise$$internal$$handleMaybeThenable(promise, value, lib$es6$promise$$internal$$getThen(value));
} else {
lib$es6$promise$$internal$$fulfill(promise, value);
}
}

function lib$es6$promise$$internal$$publishRejection(promise) {
if (promise._onerror) {
promise._onerror(promise._result);
}

lib$es6$promise$$internal$$publish(promise);
}

function lib$es6$promise$$internal$$fulfill(promise, value) {
if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }

promise._result = value;
promise._state = lib$es6$promise$$internal$$FULFILLED;

if (promise._subscribers.length !== 0) {
lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise);
}
}

function lib$es6$promise$$internal$$reject(promise, reason) {
if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; }
promise._state = lib$es6$promise$$internal$$REJECTED;
promise._result = reason;

lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise);
}

function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;

parent._onerror = null;

subscribers[length] = child;
subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment;
subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection;

if (length === 0 && parent._state) {
lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent);
}
}

function lib$es6$promise$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;

if (subscribers.length === 0) { return; }

var child, callback, detail = promise._result;

for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];

if (child) {
lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}

promise._subscribers.length = 0;
}

function lib$es6$promise$$internal$$ErrorObject() {
this.error = null;
}

var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject();

function lib$es6$promise$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e;
return lib$es6$promise$$internal$$TRY_CATCH_ERROR;
}
}

function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = lib$es6$promise$utils$$isFunction(callback),
value, error, succeeded, failed;

if (hasCallback) {
value = lib$es6$promise$$internal$$tryCatch(callback, detail);

if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}

if (promise === value) {
lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn());
return;
}

} else {
value = detail;
succeeded = true;
}

if (promise._state !== lib$es6$promise$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
lib$es6$promise$$internal$$resolve(promise, value);
} else if (failed) {
lib$es6$promise$$internal$$reject(promise, error);
} else if (settled === lib$es6$promise$$internal$$FULFILLED) {
lib$es6$promise$$internal$$fulfill(promise, value);
} else if (settled === lib$es6$promise$$internal$$REJECTED) {
lib$es6$promise$$internal$$reject(promise, value);
}
}

function lib$es6$promise$$internal$$initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
lib$es6$promise$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
lib$es6$promise$$internal$$reject(promise, reason);
});
} catch(e) {
lib$es6$promise$$internal$$reject(promise, e);
}
}

var lib$es6$promise$$internal$$id = 0;
function lib$es6$promise$$internal$$nextId() {
return lib$es6$promise$$internal$$id++;
}

function lib$es6$promise$$internal$$makePromise(promise) {
promise[lib$es6$promise$$internal$$PROMISE_ID] = lib$es6$promise$$internal$$id++;
promise._state = undefined;
promise._result = undefined;
promise._subscribers = [];
}

function lib$es6$promise$promise$all$$all(entries) {
return new lib$es6$promise$enumerator$$default(this, entries).promise;
}
var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all;
function lib$es6$promise$promise$race$$race(entries) {
/*jshint validthis:true */
var Constructor = this;

if (!lib$es6$promise$utils$$isArray(entries)) {
return new Constructor(function(resolve, reject) {
reject(new TypeError('You must pass an array to race.'));
});
} else {
return new Constructor(function(resolve, reject) {
var length = entries.length;
for (var i = 0; i < length; i++) {
Constructor.resolve(entries[i]).then(resolve, reject);
}
});
}
}
var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race;
function lib$es6$promise$promise$reject$$reject(reason) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor(lib$es6$promise$$internal$$noop);
lib$es6$promise$$internal$$reject(promise, reason);
return promise;
}
var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject;


function lib$es6$promise$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}

function lib$es6$promise$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}

var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise;
/**
Promise objects represent the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promise's eventual value or the reason
why the promise cannot be fulfilled.

Terminology
-----------

- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- `thenable` is an object or function that defines a `then` method.
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- `exception` is a value that is thrown using the throw statement.
- `reason` is a value that indicates why a promise was rejected.
- `settled` the final resting state of a promise, fulfilled or rejected.

A promise can be in one of three states: pending, fulfilled, or rejected.

Promises that are fulfilled have a fulfillment value and are in the fulfilled
state. Promises that are rejected have a rejection reason and are in the
rejected state. A fulfillment value is never a thenable.

Promises can also be said to *resolve* a value. If this value is also a
promise, then the original promise's settled state will match the value's
settled state. So a promise that *resolves* a promise that rejects will
itself reject, and a promise that *resolves* a promise that fulfills will
itself fulfill.


Basic Usage:
------------

```js
var promise = new Promise(function(resolve, reject) {
// on success
resolve(value);

// on failure
reject(reason);
});

promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
```

Advanced Usage:
---------------

Promises shine when abstracting away asynchronous interactions such as
`XMLHttpRequest`s.

```js
function getJSON(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();

xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();

function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
}
}
};
});
}

getJSON('/posts.json').then(function(json) {
// on fulfillment
}, function(reason) {
// on rejection
});
```

Unlike callbacks, promises are great composable primitives.

```js
Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values){
values[0] // => postsJSON
values[1] // => commentsJSON

return values;
});
```

@class Promise
@param {function} resolver
Useful for tooling.
@constructor
*/
function lib$es6$promise$promise$$Promise(resolver) {
this[lib$es6$promise$$internal$$PROMISE_ID] = lib$es6$promise$$internal$$nextId();
this._result = this._state = undefined;
this._subscribers = [];

if (lib$es6$promise$$internal$$noop !== resolver) {
typeof resolver !== 'function' && lib$es6$promise$promise$$needsResolver();
this instanceof lib$es6$promise$promise$$Promise ? lib$es6$promise$$internal$$initializePromise(this, resolver) : lib$es6$promise$promise$$needsNew();
}
}

lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default;
lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default;
lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default;
lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default;
lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler;
lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap;
lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap;

lib$es6$promise$promise$$Promise.prototype = {
constructor: lib$es6$promise$promise$$Promise,

/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.

```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```

Chaining
--------

The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.

```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});

findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.

```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```

Assimilation
------------

Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.

```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```

If the assimliated promise rejects, then the downstream promise will also reject.

```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```

Simple Example
--------------

Synchronous Example

```javascript
var result;

try {
result = findResult();
// success
} catch(reason) {
// failure
}
```

Errback Example

```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```

Promise Example;

```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```

Advanced Example
--------------

Synchronous Example

```javascript
var author, books;

try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```

Errback Example

```js

function foundBooks(books) {

}

function failure(reason) {

}

findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```

Promise Example;

```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```

@method then
@param {Function} onFulfilled
@param {Function} onRejected
Useful for tooling.
@return {Promise}
*/
then: lib$es6$promise$then$$default,

/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.

```js
function findAuthor(){
throw new Error('couldn't find that author');
}

// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}

// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```

@method catch
@param {Function} onRejection
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection) {
return this.then(null, onRejection);
}
};
var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator;
function lib$es6$promise$enumerator$$Enumerator(Constructor, input) {
this._instanceConstructor = Constructor;
this.promise = new Constructor(lib$es6$promise$$internal$$noop);

if (!this.promise[lib$es6$promise$$internal$$PROMISE_ID]) {
lib$es6$promise$$internal$$makePromise(this.promise);
}

if (lib$es6$promise$utils$$isArray(input)) {
this._input = input;
this.length = input.length;
this._remaining = input.length;

this._result = new Array(this.length);

if (this.length === 0) {
lib$es6$promise$$internal$$fulfill(this.promise, this._result);
} else {
this.length = this.length || 0;
this._enumerate();
if (this._remaining === 0) {
lib$es6$promise$$internal$$fulfill(this.promise, this._result);
}
}
} else {
lib$es6$promise$$internal$$reject(this.promise, lib$es6$promise$enumerator$$validationError());
}
}

function lib$es6$promise$enumerator$$validationError() {
return new Error('Array Methods must be provided an Array');
}

lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() {
var length = this.length;
var input = this._input;

for (var i = 0; this._state === lib$es6$promise$$internal$$PENDING && i < length; i++) {
this._eachEntry(input[i], i);
}
};

lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var c = this._instanceConstructor;
var resolve = c.resolve;

if (resolve === lib$es6$promise$promise$resolve$$default) {
var then = lib$es6$promise$$internal$$getThen(entry);

if (then === lib$es6$promise$then$$default &&
entry._state !== lib$es6$promise$$internal$$PENDING) {
this._settledAt(entry._state, i, entry._result);
} else if (typeof then !== 'function') {
this._remaining--;
this._result[i] = entry;
} else if (c === lib$es6$promise$promise$$default) {
var promise = new c(lib$es6$promise$$internal$$noop);
lib$es6$promise$$internal$$handleMaybeThenable(promise, entry, then);
this._willSettleAt(promise, i);
} else {
this._willSettleAt(new c(function(resolve) { resolve(entry); }), i);
}
} else {
this._willSettleAt(resolve(entry), i);
}
};

lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var promise = this.promise;

if (promise._state === lib$es6$promise$$internal$$PENDING) {
this._remaining--;

if (state === lib$es6$promise$$internal$$REJECTED) {
lib$es6$promise$$internal$$reject(promise, value);
} else {
this._result[i] = value;
}
}

if (this._remaining === 0) {
lib$es6$promise$$internal$$fulfill(promise, this._result);
}
};

lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;

lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason);
});
};
function lib$es6$promise$polyfill$$polyfill() {
var local;

if (typeof global !== 'undefined') {
local = global;
} else if (typeof self !== 'undefined') {
local = self;
} else {
try {
local = Function('return this')();
} catch (e) {
throw new Error('polyfill failed because global object is unavailable in this environment');
}
}

var P = local.Promise;

if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) {
return;
}

local.Promise = lib$es6$promise$promise$$default;
}
var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill;

lib$es6$promise$promise$$default.Promise = lib$es6$promise$promise$$default;
lib$es6$promise$promise$$default.polyfill = lib$es6$promise$polyfill$$default;

/* global define:true module:true window: true */
if (typeof define === 'function' && define['amd']) {
define(function() { return lib$es6$promise$promise$$default; });
} else if (typeof module !== 'undefined' && module['exports']) {
module['exports'] = lib$es6$promise$promise$$default;
} else if (typeof this !== 'undefined') {
this['Promise'] = lib$es6$promise$promise$$default;
}

lib$es6$promise$polyfill$$default();
}).call(this);