var comm = { data: { baseUrl: '' }, /* ====================================================================================== */ addEvent: function (ele, ev, fn) { // 添加事件的函数 //针对IE浏览器 if (ele.attachEvent) { ele.attachEvent('on' + ev, fn) } //针对FF与chrome else { ele.addEventListener(ev, fn, false) } }, ajax: function (options) { // 封装ajax var _this = this; //异步请求对象的完成状态 this.done = 0; this.format = function () { var now = new String(new Date().getTime()); return now.substr(0, now.length - 3); } //格式化参数 this.formatParams = function (data) { //获取地址参数 var arr = []; for (var name in data) { arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name])); } arr.push("t=" + _this.format());//按分钟刷一次 return arr.join("&"); } //传入设置 options = options || {}; //请求方式 options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; options.async = options.async || true; options.contentType = options.contentType || 'application/x-www-form-urlencoded'; var params = _this.formatParams(options.data); if (options.contentType == "application/json;charset=utf-8") { params = JSON.stringify(options.data) } //创建异步请求对象 - 第一步 var xhr; //w3c标准 if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } //兼容IE6及以下 else if (window.ActiveObject) { xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //连接 和 发送 - 第二步 //判断是那种类型的请求 //若是get请求 if (options.type == "GET") { //参数拼接 if (options.url.indexOf("?") == -1) sp = "?"; else sp = "&"; //发送请求 xhr.open("GET", options.url + sp + params, options.async); xhr.send(null); } //若是post请求 else if (options.type == "POST") { //发送请求 xhr.open("POST", options.url, options.async); //设置表单提交时的内容类型 xhr.setRequestHeader("Content-Type", options.contentType); //参数配置 xhr.send(params); } //接收 - 第三步 xhr.onreadystatechange = function () { if (xhr.readyState == 4) { //状态码 var status = xhr.status; //状态码表示成功时,执行成功回调函数 if (status >= 200 && status < 300 || status == 304) { //返回数据的格式 //json字符串 if (options.dataType == "json") { try { options.success && options.success(eval("(" + xhr.responseText + ")")); } catch (err) { options.success && options.success(JSON.parse(xhr.responseText), xhr.responseXML); } } //普通字符串 else { options.success && options.success(xhr.responseText, xhr.responseXML); } // 改变状态为完成 _this.done = 1; } //如果状态码表示失败时调用错误处理回调函数 else { options.error && options.error(status); // 改变状态为完成 _this.done = 1; } } } }, /* ====================================================================================== */ hasClass: function (ele, cls) { // 判断一个类是否存在 return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) }, addClass: function (ele, cls) { // 增加一个类 if (!this.hasClass(ele, cls)) ele.className = ele.className.replace(/(\s*$)/g, "") + " " + cls }, removeClass: function (ele, cls) { // 删除一个类 if (this.hasClass(ele, cls)) { var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)'); ele.className = ele.className.replace(reg, ' ') } }, getStyle: function (ele, attr) { // 获取某个元素的样式 var res = ''; if (window.getComputedStyle) { res = getComputedStyle(ele)[attr]; } else if (ele.currentStyle) { res = ele.currentStyle[attr]; } else { res = ele.style[attr]; } // 这里返回的样式做了调整,返回必须为字符串,有盒子的样式获取像margin-left会返回纯数字(不含单位px),这样不好处理,统一变成字符串后再对返回结果用正则匹配 return res + ''; }, /* ====================================================================================== */ show: function (ele) { // 让一个元素隐藏(display) ele.style.display = 'block' }, hide: function (ele) { // 让一个元素显示(display) ele.style.display = 'none' }, isShow: function (ele) { // 判断某个元素的是否显示(display,浅) var getVisibility = ele.style.display; return getVisibility !== "none"; }, isShowDeel: function (ele) { // 判断某个元素是否显示(display,深) temp = ele var getVisibility = this.getStyle(temp, 'display'); if (getVisibility == 'none') { return false; } else if (temp.tagName == 'BODY') { return true; } else { return this.isShowDeel(temp.parentNode); } }, visible: function (ele) { // 让一个元素隐藏(visibility) ele.style.visibility = 'visible' }, hidden: function (ele) { // 让一个元素显示(visibility) ele.style.visibility = 'hidden' }, visibleClass: function (cls) { // 让一个类的元素隐藏(visibility) var arr = document.getElementsByClassName(cls) for (var i = 0; i < arr.length; i++) { arr[i].style.visibility = 'visible' } }, hiddenClass: function (cls) { // 让一个类的元素显示(visibility) var arr = document.getElementsByClassName(cls) for (var i = 0; i < arr.length; i++) { arr[i].style.visibility = 'hidden' } }, /* ====================================================================================== */ addElement: function (ele, tag, cls, data, inner, fn) { // 为一个元素创建一个子元素 // 1、创建新元素 var newEle = document.createElement(tag) // 2、设置各种属性(图片地址,自定义属性等) newEle.setAttribute('class', cls); for (var item in data) { newEle.setAttribute(item, data[item]); } // 3、设置内容(innerhtml) newEle.innerHTML = inner ? inner : '' // 4、设置回调函数 fn && fn(newEle) // 5、将新元素加入到父元素中 ele.appendChild(newEle) }, // 帧动画(定时器容器(存在一个对象内的一个属性),图片群所在的元素,执行速度(单位:毫秒),是否只执行一次,执行完毕的回调函数) zhenAnimation: function (interval, ele, speed, once, fn) { var cont = document.getElementsByClassName('container')[0] // 清除定时器 clearInterval(cont[interval]) // 获取图片群并全部隐藏 var imgs = ele.getElementsByTagName('img') for (var i = 0; i < imgs.length; i++) { imgs[i].style.visibility = 'hidden' } // 单独显示第一张图 var i = 0 imgs[i].style.visibility = 'visible' // 设置定时器 cont[interval] = setInterval(function() { // 判断是否只执行一次 if (i == imgs.length-1 && once) { // 每轮执行完成的回调函数 clearInterval(cont[interval]) fn&&fn() return } // 前一张图隐藏、后一张图显现、可循环执行 imgs[i++].style.visibility = 'hidden' if (i == imgs.length) {i=0; fn&&fn()} imgs[i].style.visibility = 'visible' }, speed) }, // 帧动画加强版,ele格式:
zhenAnimationPro: function (interval, ele, speed, once, fn) { // 判断是否第一次执行该帧动画,是则加载图片 if (!ele.getAttribute('isload')) { var src = ele.getAttribute('data-url') for (var j = ele.getAttribute('data-max'); j >= 0; j--) { ele.innerHTML = '' + ele.innerHTML } ele.setAttribute('isload', 1) } var cont = document.getElementsByClassName('container')[0] // 清除定时器 clearInterval(cont[interval]) // 获取图片群并全部隐藏 var imgs = ele.getElementsByTagName('img') for (var i = 0; i < imgs.length; i++) { imgs[i].style.visibility = 'hidden' } // 单独显示第一张图 var i = 0 imgs[i].style.visibility = 'visible' // 设置定时器 cont[interval] = setInterval(function() { // 判断是否只执行一次 if (i == imgs.length-1 && once) { // 每轮执行完成的回调函数 clearInterval(cont[interval]) fn&&fn() return } // 前一张图隐藏、后一张图显现、可循环执行 imgs[i++].style.visibility = 'hidden' if (i == imgs.length) {i=0; fn&&fn()} imgs[i].style.visibility = 'visible' }, speed) }, /* ====================================================================================== */ setCookie: function (name, value, t) { // 设置cookie var hour = t ? t : 8; var exp = new Date(); exp.setTime(exp.getTime() + hour * 60 * 60 * 1000); document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString() + ";path=/"; }, getCookie: function (name) { // 获取cookie 存在返回值,不存在返回null var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) { if (arr[2] != "undefined") return unescape(arr[2]); else return undefined; } else { return null; } }, /* ====================================================================================== */ getQueryString: function (name) { // 获取url的某个参数 var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null && unescape(r[2]) != "undefined" && unescape(r[2]) != "null") return unescape(r[2]); return ''; }, urlParam: function (obj) { // 将对象转换为url参数字符串 var _this = this; var arr = []; for (var name in obj) { arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(obj[name])); } return arr.join("&"); }, getRandom: function (min, max) { // 获取随机数 return Math.floor(Math.random() * (max - min)) + min; }, arrRandom: function (arr) { // 使数组随机排序,返回一个新数组 arr.sort(function () { return 0.5 - Math.random() }) }, createArr: function (arr, num, content) { // 生成数组, // 调用举例:comm.createArr(arr, 'num', 'content') // 输出举例:var arr = [{num: 5, content: {id: 1, imgurl: 'img/1.jpg'}}, {num: 2, content: {id: 2, imgurl: 'img/2.jpg'}}] var newArr = [] for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr[i][num]; j++) { newArr.push(arr[i][content]) } } return newArr }, /* ====================================================================================== */ isPhone: function (phone) { // 判断是否为有效手机号 if (!(/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(phone))) { return false; } else { return true } }, timestamp: function (time) { // 转换时间格式过滤器 var sec = Math.floor(time % 60) var min = Math.floor(time / 60 % 60) var hour = Math.floor(time / 60 / 60) sec = sec < 10 ? '0' + sec : sec min = min < 10 ? '0' + min : min hour = hour < 10 ? '0' + hour : hour var timeStr = hour + ':' + min + ':' + sec; return timeStr }, addPreZero: function (num) { // 帧动画补零过滤器 if (num < 10) { return '0000' + num; } else if (num < 100) { return '000' + num; } else if (num < 1000) { return '00' + num; } else if (num < 10000) { return '0' + num; } else { return num; } }, /* ====================================================================================== */ Debuglog: function (text) { // 弹窗,用于测试 if (typeof printWind == "undefined") { window.printWind = document.createElement("div"); window.inner = document.createElement("div"); inner.style.width = "600px"; inner.style.position = "absolute"; inner.style.right = "0px"; printWind.appendChild(inner); printWind.style.position = "fixed"; printWind.style.right = "0"; printWind.style.top = "0"; printWind.style.background = "rgba(0,0,0,0.6)"; printWind.style.zIndex = "99999"; printWind.style.padding = "20px"; printWind.style.fontSize = "20px"; printWind.style.width = "600px"; printWind.style.height = "600px"; printWind.style.color = "#0aff08"; document.body.appendChild(printWind); } var para = document.createElement("p"); //创建新的

元素 para.innerHTML = text; para.setAttribute("class", "newLine"); para.style.padding = "5px"; inner.appendChild(para); var a = inner.clientHeight - 600; inner.style.top = -a + "px"; }, tips: function (text, time) { time = time ? time : 1500; var para = document.createElement("div"); //创建新的

元素 para.innerHTML = text; para.style.zIndex = 10000; para.style.borderRadius = '9px' para.style.backgroundColor = '#287AFF' para.style.textAlign = 'center' para.style.color = '#FFF' para.style.position = 'absolute' para.style.fontSize = '20px' para.style.left = '450px' para.style.top = '250px' para.style.padding = '7px 27px' para.style.width = '380px' para.style.wordBreak = 'break-all' para.style.display = 'block' document.body.appendChild(para); setTimeout(function () { document.body.removeChild(para); }, time); }, /* ====================================================================================== */ STBUtil: { /** * 通过键值获取机顶盒对应信息 * @param name [参数名] ex:UserToken--用户token,EPGDomain--EPG域名,areaid--地区编码,templateName--当前用户模板 * @return [] */ getSTBKey: function (name) { var value = ''; if (typeof (Authentication) === "object") { if (Authentication.CTCGetConfig) { value = Authentication.CTCGetConfig(name); } else if (Authentication.CUGetConfig) { value = Authentication.CUGetConfig(name); } } return value; }, /** * 通过键值设置机顶盒对应信息 * @param name [参数名] * @param value [参数值] */ setSTBKey: function (name, value) { if (typeof (Authentication) === "object") { Authentication.CTCSetConfig(name, value); } }, /** * 获取机顶盒 用户账号/业务账号 * @return {string} */ getSTBUserId: function () { var userId = ''; try{ if (typeof (Authentication) == 'object') { // 此方法经测试目前可以获取到华为,中兴,创维三款机顶盒型号 userId = Authentication.CTCGetConfig('UserID'); if (!userId){ userId = Authentication.CUGetConfig("UserID"); } //烽火的机顶盒 if(!userId){ userId =Authentication.CTCGetConfig("device.userid"); } //中兴老的盒子获取机顶盒型号的方法 if(!userId && typeof(ztebw) == 'object' ){ stbModel = ztebw.ioctlRead("infoZTEHWType"); if(!stbModel) { stbModel = ztebw.ioctlRead("infoHWProduct"); } } } else{ console.log("不支持Authentication!"); } } catch(e){ userId = ''; } return userId; }, /** * 获取机顶盒 设备ID * @return {string} */ getSTBId: function () { var stbId = ""; if (typeof (Authentication) == "object") { stbId = Authentication.CTCGetConfig("STBID"); if (!stbId) { stbId = Authentication.CUGetConfig("STBID"); } if (!stbId) { stbId = Authentication.CTCGetConfig("device.stbid"); // 烽火的机顶盒 } } // 广西广电获取stbId if (!stbId && typeof (guangxi) === "object") { stbId = guangxi.getStbNum(); } return stbId; }, /** * 获取机顶盒型号 * @return {string} */ getSTBModel: function () { var stbModel = ''; try{ //此方法经测试目前可以获取到华为,中兴,创维三款机顶盒型号 stbModel = Authentication.CTCGetConfig('STBType'); if (!stbModel){ stbModel = Authentication.CUGetConfig("STBType"); } //烽火的机顶盒 if(!stbModel){ stbModel = Authentication.CTCGetConfig("device.stbmodel"); } //中兴老的盒子获取机顶盒型号的方法 if(!stbModel && typeof(ztebw) == 'object' ){ stbModel = ztebw.ioctlRead("infoZTEHWType"); if(!stbModel){ stbModel = ztebw.ioctlRead("infoHWProduct"); } } } catch(e){ console.log("不支持获取机顶盒型号!"); } return stbModel; }, /** * 获取机顶盒mac地址 * @return {string} */ getSTBMac: function () { if (window.isWinOS) { //Windows操作系统 return "00-00-00-00-00-00"; } var mac = ""; if (typeof (Authentication) == "object") { try { mac = Authentication.CUGetConfig("mac"); if (!mac && typeof (ztebw) == "object") { var stbId = ztebw.ioctlRead("infoHWSN"); mac = stbId.substring(stbId.length - 12); } if (!mac) { mac = Authentication.CTCGetLocalMAC(); } } catch (e) { } } // 广西广电获取mac if (!mac && typeof iPanel === "object") { mac = iPanel.getGlobalVar("MAC_ETH0"); } // 长虹机顶盒获取mac(四川广电) if (!mac && typeof (Ethernet) === "object") { mac = Ethernet.MACAddress; } if (mac) { while (mac.indexOf(":") !== -1) { mac = mac.replace(":", ""); } } else { mac = "00-00-00-00-00-00"; } return mac; }, /** * 获取 EPG大厅地址 * @return {string} */ getEPGDomain: function () { var epgDomain = ""; if (typeof (Authentication) == "object") { epgDomain = Authentication.CTCGetConfig("EPGDomain"); if (!epgDomain) { epgDomain = Authentication.CUGetConfig("EPGDomain"); } if (typeof epgDomain === "undefined" || epgDomain == null) { epgDomain = ""; } } return epgDomain; }, /** * 获取 UserToken * @return {string} */ getUserToken: function () { var userToken = ""; if (typeof (Authentication) == "object") { userToken = Authentication.CTCGetConfig("UserToken"); if (!userToken) { userToken = Authentication.CUGetConfig("UserToken"); } if (!userToken) { userToken = Authentication.CTCGetConfig("device.usertoken"); } } return userToken; }, } }; // promise插件 (function (window) { // 参考Joe-Xie:https://www.cnblogs.com/XieJunBao/p/9156134.html // 原生封装promise为了应对低版本浏览器不兼容问题 // 异步串行思路:promise执行then是注册回调函数,then有多个就可以注册多个回调函数,但是若多个回调都是异步执行的,那我们要等上一个异步结束后才执行下一个异步,这是时候就需要上一个异步操作完成后,把这个完成状态告诉下一个回调,这样才可以异步串行。为了解决这个问题我们把异步完成状态托管给promise去管理 // 流程:第一步注册:链式调用then函数,每执行一个then函数,返回一个桥梁promise(then函数中的成功回调和失败回调是写入这个promise的回调列表中的,注意成功回调的功能除了执行本身函数外还要更新下一个promise的状态) // 第二步执行:第一个promise的异步执行完,开始执行第一个promise的回调函数(回调函数又分两步走:第一步:resolvePromise解析回调返回值(如果是promise则说明是异步,就需要继续解析直到不是promise而是一个具体的值),第二步:当回调返回的值是一个具体值而不是promise时,调用第二个proomise的reslove方法将第二个proomise的状态更新为fulfilled,并将第一个promise的回调的值传入p2的回调函数中去执行) function MyPromise(fn) { var self = this; // 成功回调传的参数 self.value = null; // 失败回调传的参数 self.error = null; // 当前promise对象的状态 self.status = "pending"; // 存储成功回调列表 self.onFulfilledCallbacks = []; // 存储失败回调列表 self.onRejectedCallbacks = []; // 状态改变并执行回调 // 成功 function resolve(value) { // 判断传入参数是否由MyPromise构造的对象,若是,注册该函数 if (value instanceof MyPromise) { return value.then(resolve, reject); } // 判断 if (self.status === "pending") { setTimeout(function () { self.status = "fulfilled"; self.value = value; // 执行成功回调 // self.onFulfilledCallbacks.forEach(function(callback){callback(self.value)}); // 向下兼容forEach for (var i = 0; i < self.onFulfilledCallbacks.length; i++) { self.onFulfilledCallbacks[i](self.value); } }, 0) } } // 失败 function reject(error) { if (self.status === "pending") { setTimeout(function () { self.status = "rejected"; self.error = error; // self.onRejectedCallbacks.forEach(function(callback){callback(self.error)}); for (var i = 0; i < self.onRejectedCallbacks.length; i++) { self.onRejectedCallbacks[i](self.error); } }, 0) } } try { fn(resolve, reject); } catch (e) { reject(e); } } // 解析放回值 // 用来解析回调函数的返回值x,x可能是普通值也可能是个promise对象 // 因为回调函数既可能会返回一个异步的promise也可能会返回一个同步结果,所以我们把直接把回调函数的结果托管给bridgePromise,使用resolvePromise方法来解析回调函数的结果,如果回调函数返回一个promise并且状态还是pending,就在这个promise的then方法中继续解析这个promise reslove传过来的值,如果值还是pending状态的promise就继续解析,直到不是一个异步promise,而是一个正常值就使用bridgePromise的reslove方法将bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入,到此异步操作就衔接上了。 function resolvePromise(bridgepromise, x, resolve, reject) { // bridgepromise是桥梁promise,x是桥梁promise中注册的成功回调的返回值,resolve和reject是桥梁promise的状态改变函数 // 2.3.1规范,避免循环引用 // 如果成功回调的值又是桥梁promise就返回循环传参的错误(死循环) if (bridgepromise === x) { return reject(new TypeError('Circular reference')); } var called = false; // // 如果x是一个promise,则通过递归 // if (x instanceof MyPromise) { // //如果这个promise是pending状态,就在它的then方法里继续执行resolvePromise解析它的结果,直到返回值不是一个pending状态的promise为止(这里使用了递归的方法) // if (x.status === "pending") { // x.then( // function(y){ // resolvePromise(bridgepromise, y, resolve, reject); // }, // function(error){ // reject(error); // } // ); // } // else { // x.then(resolve, reject); // } // } // else // // 如果x是一个promise,则继续解析它的状态 if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) { try { var then = x.then; if (typeof then === 'function') { // then方法的指向传入的桥梁promise,也就是说该桥梁promise调用了then方法并传入了成功回调和失败回调 then.call( x, // 传入then的成功回调 function (y) { if (called) return; called = true; // 这里重新解析当前的桥梁promise,至于成功回调的返回值传空(这里目的是通过递归持续判断当前桥梁promise的状态) resolvePromise(bridgepromise, y, resolve, reject); }, //传入then的失败回调 function (error) { if (called) return; called = true; reject(error); } ) } // 如果then不是一个函数,则以x为值改变promise状态并延长成功回调列表 else { resolve(x); } } // 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。 catch (e) { if (called) return; called = true; reject(e); } } // 如过x不是一个promise,则改变bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入 else { resolve(x); } } // 注册回调函数 MyPromise.prototype.then = function (onFulfilled, onRejected) { var self = this; // 搭建桥梁promise(即调用为then方法后重新返回一个新的promise对象) var bridgePromise; // 防止使用者不传成功或失败回调函数,所以成功失败回调都给了默认回调函数 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) { return value }; onRejected = typeof onRejected === "function" ? onRejected : function (error) { throw error }; // 如果当前的promise对象是完成状态 // 返回一个新的桥梁promise if (self.status === "fulfilled") { return bridgePromise = new MyPromise(function (resolve, reject) { setTimeout(function () { try { // 获取成功回调函数的返回值 var x = onFulfilled(self.value); // 解析桥梁promise函数 resolvePromise(bridgePromise, x, resolve, reject); } catch (e) { reject(e); } }, 0); }) } // 如果当前的promise对象是拒绝状态 if (self.status === "rejected") { return bridgePromise = new MyPromise(function (resolve, reject) { setTimeout(function () { try { var x = onRejected(self.error); resolvePromise(bridgePromise, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); } // 如果当前的promise对象是听候状态,则在当前promise对象的成功回调列表和失败回调列表中注入 if (self.status === "pending") { return bridgePromise = new MyPromise(function (resolve, reject) { // 注意回调列表是把整个回调函数和回调解析函数一起注入的!!!!!,所以在执行回调时除运行回调函数还要,解析桥梁promise的状态(有可能桥梁promise中也有promise),解析中改变当前promise的状态,若当前promise的状态为完成状态才继续执行下一个注册好的回调 self.onFulfilledCallbacks.push(function (value) { try { var x = onFulfilled(value); resolvePromise(bridgePromise, x, resolve, reject); } catch (e) { reject(e); } }); self.onRejectedCallbacks.push(function (error) { try { var x = onRejected(error); resolvePromise(bridgePromise, x, resolve, reject); } catch (e) { reject(e); } }); }); } } MyPromise.prototype.MyCatch = function (onRejected) { return this.then(null, onRejected); } MyPromise.all = function (promises) { return new MyPromise(function (resolve, reject) { var result = []; var count = 0; for (var i = 0; i < promises.length; i++) { // (function(i){ // return promises[i].then(function(data) { // result[i] = data; // if (++count == promises.length) { // resolve(result); // } // }, function(error) { // reject(error); // }); // })(i) function closeTemp(i) { return promises[i].then(function (data) { result[i] = data; if (++count == promises.length) { resolve(result); } }, function (error) { reject(error); }); } closeTemp(i) } }); } MyPromise.race = function (promises) { return new MyPromise(function (resolve, reject) { for (var i = 0; i < promises.length; i++) { promises[i].then(function (data) { resolve(data); }, function (error) { reject(error); }); } }); } MyPromise.resolve = function (value) { return new MyPromise(function (resolve) { resolve(value); }); } MyPromise.reject = function (error) { return new MyPromise(function (resolve, reject) { reject(error); }); } MyPromise.promisify = function (fn) { return function () { var args = Array.from(arguments); return new MyPromise(function (resolve, reject) { fn.apply(null, args.concat(function (err) { err ? reject(err) : resolve(arguments[1]) })); }) } } window.MyPromise = MyPromise; })(window);