common.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. var comm = {
  2. data: {
  3. baseUrl: '',
  4. },
  5. /* ====================================================================================== */
  6. addEvent: function (ele, ev, fn) { // 添加事件的函数
  7. //针对IE浏览器
  8. if (ele.attachEvent) {
  9. ele.attachEvent('on' + ev, fn)
  10. }
  11. //针对FF与chrome
  12. else {
  13. ele.addEventListener(ev, fn, false)
  14. }
  15. },
  16. ajax: function (options) { // 封装ajax
  17. var _this = this;
  18. // 创建时间戳,确保每一秒的请求是不同的
  19. this.format = function () {
  20. var now = new String(new Date().getTime());
  21. return now.substr(0, now.length - 3);
  22. }
  23. //格式化参数
  24. this.formatParams = function (data) {
  25. //获取地址参数
  26. var arr = [];
  27. for (var name in data) {
  28. arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
  29. }
  30. arr.push("t=" + _this.format()); //按分钟刷一次
  31. return arr.join("&");
  32. }
  33. //异步请求对象的完成状态
  34. this.done = 0;
  35. //传入设置
  36. options = options || {};
  37. //请求方式
  38. options.type = (options.type || "GET").toUpperCase();
  39. options.dataType = options.dataType || "json";
  40. options.async = options.async || true;
  41. var params = _this.formatParams(options.data);
  42. //创建异步请求对象 - 第一步
  43. var xhr;
  44. //w3c标准
  45. if (window.XMLHttpRequest) {
  46. xhr = new XMLHttpRequest();
  47. }
  48. //兼容IE6及以下
  49. else if (window.ActiveObject) {
  50. xhr = new ActiveXObject('Microsoft.XMLHTTP');
  51. }
  52. //连接 和 发送 - 第二步
  53. //判断是那种类型的请求
  54. //若是get请求
  55. if (options.type == "GET") {
  56. //参数拼接
  57. if (options.url.indexOf("?") == -1) sp = "?";
  58. else sp = "&";
  59. //发送请求
  60. xhr.open("GET", options.url + sp + params, options.async);
  61. xhr.send(null);
  62. }
  63. //若是post请求
  64. else if (options.type == "POST") {
  65. //发送请求
  66. xhr.open("POST", options.url, options.async);
  67. //设置表单提交时的内容类型
  68. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  69. //参数配置
  70. xhr.send(params);
  71. }
  72. //接收 - 第三步
  73. xhr.onreadystatechange = function () {
  74. if (xhr.readyState == 4) {
  75. //状态码
  76. var status = xhr.status;
  77. //状态码表示成功时,执行成功回调函数
  78. if (status >= 200 && status < 300 || status == 304) {
  79. //返回数据的格式
  80. //json字符串
  81. if (options.dataType == "json") {
  82. try {
  83. options.success && options.success(eval("(" + xhr.responseText + ")"));
  84. } catch (err) {
  85. options.success && options.success(JSON.parse(xhr.responseText), xhr.responseXML);
  86. }
  87. }
  88. //普通字符串
  89. else {
  90. options.success && options.success(xhr.responseText, xhr.responseXML);
  91. }
  92. // 改变状态为完成
  93. _this.done = 1;
  94. }
  95. //如果状态码表示失败时调用错误处理回调函数
  96. else {
  97. options.error && options.error(status);
  98. // 改变状态为完成
  99. _this.done = 1;
  100. }
  101. }
  102. }
  103. },
  104. /* ====================================================================================== */
  105. hasClass: function (ele, cls) { // 判断一个类是否存在
  106. return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
  107. },
  108. addClass: function (ele, cls) { // 增加一个类
  109. if (!this.hasClass(ele, cls)) ele.className = ele.className.replace(/(\s*$)/g, "") + " " + cls
  110. },
  111. removeClass: function (ele, cls) { // 删除一个类
  112. if (this.hasClass(ele, cls)) {
  113. var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
  114. ele.className = ele.className.replace(reg, ' ')
  115. }
  116. },
  117. getStyle: function (ele, attr) { // 获取某个元素的样式
  118. var res = '';
  119. if (window.getComputedStyle) {
  120. res = getComputedStyle(ele)[attr];
  121. } else if (ele.currentStyle) {
  122. res = ele.currentStyle[attr];
  123. } else {
  124. res = ele.style[attr];
  125. }
  126. // 这里返回的样式做了调整,返回必须为字符串,有盒子的样式获取像margin-left会返回纯数字(不含单位px),这样不好处理,统一变成字符串后再对返回结果用正则匹配
  127. return res + '';
  128. },
  129. /* ====================================================================================== */
  130. show: function (ele) { // 让一个元素隐藏(display)
  131. ele.style.display = 'block'
  132. },
  133. hide: function (ele) { // 让一个元素显示(display)
  134. ele.style.display = 'none'
  135. },
  136. isShow: function (ele) { // 判断某个元素的是否显示(display,浅)
  137. var getVisibility = ele.style.display;
  138. return getVisibility !== "none";
  139. },
  140. isShowDeel: function (ele) { // 判断某个元素是否显示(display,深)
  141. temp = ele
  142. var getVisibility = this.getStyle(temp, 'display');
  143. if (getVisibility == 'none') {
  144. return false;
  145. } else if (temp.tagName == 'BODY') {
  146. return true;
  147. } else {
  148. return this.isShowDeel(temp.parentNode);
  149. }
  150. },
  151. visible: function (ele) { // 让一个元素隐藏(visible)
  152. ele.style.visibility = 'visible'
  153. },
  154. hidden: function (ele) { // 让一个元素显示(visible)
  155. ele.style.visibility = 'hidden'
  156. },
  157. /* ====================================================================================== */
  158. addElement: function (ele, tag, cls, data, inner, fn) { // 为一个元素创建一个子元素
  159. // 1、创建新元素
  160. var newEle = document.createElement(tag)
  161. // 2、设置各种属性(图片地址,自定义属性等)
  162. newEle.setAttribute('class', cls);
  163. for (var item in data) {
  164. newEle.setAttribute(item, data[item]);
  165. }
  166. // 3、设置内容(innerhtml)
  167. newEle.innerHTML = inner ? inner : ''
  168. // 4、设置回调函数
  169. fn && fn(newEle)
  170. // 5、将新元素加入到父元素中
  171. ele.appendChild(newEle)
  172. },
  173. /* ====================================================================================== */
  174. setCookie: function (name, value, time) { // 设置cookie
  175. var hour = t ? t : 8;
  176. var exp = new Date();
  177. exp.setTime(exp.getTime() + hour * 60 * 60 * 1000);
  178. document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString() + ";path=/";
  179. },
  180. getCookie: function (name) { // 获取cookie 存在返回值,不存在返回null
  181. var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
  182. if (arr = document.cookie.match(reg)) {
  183. if (arr[2] != "undefined")
  184. return unescape(arr[2]);
  185. else return undefined;
  186. } else {
  187. return null;
  188. }
  189. },
  190. getStack: function (stackName) { //获取历史栈
  191. var _this = this;
  192. var stack;
  193. if (_this.getQueryString('stack')) {
  194. stack = JSON.parse(_this.getQueryString('stack'));
  195. } else if (
  196. _this.getCookie(stackName) && JSON.parse(_this.getCookie(stackName))
  197. ) {
  198. stack = JSON.parse(_this.getCookie(stackName))
  199. }
  200. // 如果cookie上没有,就把上一页路径做为返回路径
  201. else {
  202. stack = [];
  203. }
  204. return stack;
  205. },
  206. pushStack: function (stackName, url) { // 添加历史栈
  207. var _this = this;
  208. var stack;
  209. stack = _this.getStack(stackName);
  210. stack.push(url);
  211. _this.setCookie('stackName', JSON.stringify(stack));
  212. _this.setCookie(stackName, JSON.stringify(stack));
  213. },
  214. popStack: function (stackName) { // 删除历史栈
  215. var _this = this;
  216. var stack;
  217. var delTop;
  218. stack = _this.getStack(stackName);
  219. delTop = stack.pop();
  220. _this.setCookie(stackName, JSON.stringify(stack));
  221. return delTop;
  222. },
  223. /* ====================================================================================== */
  224. getQueryString: function (name) { // 获取url的某个参数
  225. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  226. var r = window.location.search.substr(1).match(reg);
  227. if (r != null && unescape(r[2]) != "undefined" && unescape(r[2]) != "null") return unescape(r[2]);
  228. return '';
  229. },
  230. urlParam: function (obj) { // 将对象转换为url参数字符串
  231. var _this = this;
  232. var arr = [];
  233. for (var name in obj) {
  234. arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(obj[name]));
  235. }
  236. return arr.join("&");
  237. },
  238. /* ====================================================================================== */
  239. isPoneAvailable: function (pone) { // 判断是否为有效手机号
  240. var myreg = /^[1][3,4,5,7,8][0-9]{9}$/;
  241. if (!myreg.test(pone)) {
  242. return false;
  243. } else {
  244. return true;
  245. }
  246. },
  247. computeTimeStr: function (time) { // 转换时间格式
  248. var sec = Math.floor(time % 60)
  249. var min = Math.floor(time / 60 % 60)
  250. var hour = Math.floor(time / 60 / 60)
  251. sec = sec < 10 ? '0' + sec : sec
  252. min = min < 10 ? '0' + min : min
  253. hour = hour < 10 ? '0' + hour : hour
  254. var timeStr = hour + ':' + min + ':' + sec;
  255. return timeStr
  256. },
  257. /* ====================================================================================== */
  258. Debuglog: function (text) { // 弹窗,用于测试
  259. if (typeof printWind == "undefined") {
  260. window.printWind = document.createElement("div");
  261. window.inner = document.createElement("div");
  262. inner.style.width = "600px";
  263. inner.style.position = "absolute";
  264. inner.style.right = "0px";
  265. printWind.appendChild(inner);
  266. printWind.style.position = "fixed";
  267. printWind.style.right = "0";
  268. printWind.style.top = "0";
  269. printWind.style.background = "rgba(0,0,0,0.6)";
  270. printWind.style.zIndex = "99999";
  271. printWind.style.padding = "20px";
  272. printWind.style.fontSize = "20px";
  273. printWind.style.width = "600px";
  274. printWind.style.height = "600px";
  275. printWind.style.color = "#0aff08";
  276. document.body.appendChild(printWind);
  277. }
  278. var para = document.createElement("p"); //创建新的<p> 元素
  279. para.innerHTML = text;
  280. para.setAttribute("class", "newLine");
  281. para.style.padding = "5px";
  282. inner.appendChild(para);
  283. var a = inner.clientHeight - 600;
  284. inner.style.top = -a + "px";
  285. },
  286. STBUtil: {
  287. /**
  288. * 通过键值获取机顶盒对应信息
  289. * @param name [参数名] ex:UserToken--用户token,EPGDomain--EPG域名,areaid--地区编码,templateName--当前用户模板
  290. * @return []
  291. */
  292. getSTBKey: function (name) {
  293. var value = '';
  294. if (typeof (Authentication) === "object") {
  295. if (Authentication.CTCGetConfig) {
  296. value = Authentication.CTCGetConfig(name);
  297. } else if (Authentication.CUGetConfig) {
  298. value = Authentication.CUGetConfig(name);
  299. }
  300. }
  301. return value;
  302. },
  303. /**
  304. * 通过键值设置机顶盒对应信息
  305. * @param name [参数名]
  306. * @param value [参数值]
  307. */
  308. setSTBKey: function (name, value) {
  309. if (typeof (Authentication) === "object") {
  310. Authentication.CTCSetConfig(name, value);
  311. }
  312. },
  313. /**
  314. * 获取机顶盒 用户账号/业务账号
  315. * @return {string}
  316. */
  317. getUserId: function () {
  318. var stbUID = "";
  319. if (typeof (Authentication) === "object") {
  320. //此方法经测试目前可以获取到华为,中兴,创维三款机顶盒型号
  321. stbUID = Authentication.CTCGetConfig("UserID");
  322. if (!stbUID) {
  323. stbUID = Authentication.CUGetConfig("UserID");
  324. }
  325. if (!stbUID) {
  326. // 安徽电信 创维盒子需要用username来获取业务帐号
  327. stbUID = Authentication.CTCGetConfig("username");
  328. }
  329. if (!stbUID) {
  330. stbUID = Authentication.CUGetConfig("username");
  331. }
  332. // 烽火的机顶盒
  333. if (!stbUID) {
  334. stbUID = Authentication.CTCGetConfig("device.userid");
  335. }
  336. }
  337. // 中兴老的盒子获取机顶盒型号的方法
  338. if (!stbUID && typeof (ztebw) == "object") {
  339. stbModel = ztebw.ioctlRead("infoZTEHWType");
  340. if (!stbModel) {
  341. stbModel = ztebw.ioctlRead("infoHWProduct");
  342. }
  343. }
  344. // 长虹机顶盒获取账号(四川广电:智能卡号)方法
  345. if (!stbUID && typeof (CAManager) === "object") {
  346. stbUID = CAManager.cardSerialNumber;
  347. }
  348. return stbUID;
  349. },
  350. /**
  351. * 获取机顶盒 设备ID
  352. * @return {string}
  353. */
  354. getSTBId: function () {
  355. var stbId = "";
  356. if (typeof (Authentication) == "object") {
  357. stbId = Authentication.CTCGetConfig("STBID");
  358. if (!stbId) {
  359. stbId = Authentication.CUGetConfig("STBID");
  360. }
  361. if (!stbId) {
  362. stbId = Authentication.CTCGetConfig("device.stbid"); // 烽火的机顶盒
  363. }
  364. }
  365. // 广西广电获取stbId
  366. if (!stbId && typeof (guangxi) === "object") {
  367. stbId = guangxi.getStbNum();
  368. }
  369. return stbId;
  370. },
  371. /**
  372. * 获取机顶盒型号
  373. * @return {string}
  374. */
  375. getSTBModel: function () {
  376. var stbModel = "";
  377. if (typeof (Authentication) == "object") {
  378. // 此方法经测试目前可以获取到华为,中兴,创维三款机顶盒型号
  379. stbModel = Authentication.CTCGetConfig("STBType");
  380. if (!stbModel) {
  381. stbModel = Authentication.CUGetConfig("STBType");
  382. }
  383. if (!stbModel) {
  384. stbModel = Authentication.CTCGetConfig("device.stbmodel"); // 烽火的机顶盒
  385. }
  386. }
  387. // 中兴老的盒子获取机顶盒型号的方法
  388. if (!stbModel && typeof (ztebw) == "object") {
  389. stbModel = ztebw.ioctlRead("infoZTEHWType");
  390. if (!stbModel) {
  391. stbModel = ztebw.ioctlRead("infoHWProduct");
  392. }
  393. }
  394. // 长虹机顶盒获取型号(四川广电)
  395. if (!stbModel && typeof (HardwareInfo) === "object" && typeof (HardwareInfo.STB) === "object") {
  396. stbModel = HardwareInfo.STB.model;
  397. }
  398. return stbModel;
  399. },
  400. /**
  401. * 获取机顶盒mac地址
  402. * @return {string}
  403. */
  404. getSTBMac: function () {
  405. if (window.isWinOS) { //Windows操作系统
  406. return "00-00-00-00-00-00";
  407. }
  408. var mac = "";
  409. if (typeof (Authentication) == "object") {
  410. try {
  411. mac = Authentication.CUGetConfig("mac");
  412. if (!mac && typeof (ztebw) == "object") {
  413. var stbId = ztebw.ioctlRead("infoHWSN");
  414. mac = stbId.substring(stbId.length - 12);
  415. }
  416. if (!mac) {
  417. mac = Authentication.CTCGetLocalMAC();
  418. }
  419. } catch (e) {}
  420. }
  421. // 广西广电获取mac
  422. if (!mac && typeof iPanel === "object") {
  423. mac = iPanel.getGlobalVar("MAC_ETH0");
  424. }
  425. // 长虹机顶盒获取mac(四川广电)
  426. if (!mac && typeof (Ethernet) === "object") {
  427. mac = Ethernet.MACAddress;
  428. }
  429. if (mac) {
  430. while (mac.indexOf(":") !== -1) {
  431. mac = mac.replace(":", "");
  432. }
  433. } else {
  434. mac = "00-00-00-00-00-00";
  435. }
  436. return mac;
  437. },
  438. /**
  439. * 获取 EPG大厅地址
  440. * @return {string}
  441. */
  442. getEPGDomain: function () {
  443. var epgDomain = "";
  444. if (typeof (Authentication) == "object") {
  445. epgDomain = Authentication.CTCGetConfig("EPGDomain");
  446. if (!epgDomain) {
  447. epgDomain = Authentication.CUGetConfig("EPGDomain");
  448. }
  449. if (typeof epgDomain === "undefined" || epgDomain == null) {
  450. epgDomain = "";
  451. }
  452. }
  453. return epgDomain;
  454. },
  455. /**
  456. * 获取 UserToken
  457. * @return {string}
  458. */
  459. getUserToken: function () {
  460. var userToken = "";
  461. if (typeof (Authentication) == "object") {
  462. userToken = Authentication.CTCGetConfig("UserToken");
  463. if (!userToken) {
  464. userToken = Authentication.CUGetConfig("UserToken");
  465. }
  466. if (!userToken) {
  467. userToken = Authentication.CTCGetConfig("device.usertoken");
  468. }
  469. }
  470. return userToken;
  471. },
  472. }
  473. };
  474. // promise插件
  475. (function (window) {
  476. // 参考Joe-Xie:https://www.cnblogs.com/XieJunBao/p/9156134.html
  477. // 原生封装promise为了应对低版本浏览器不兼容问题
  478. // 异步串行思路:promise执行then是注册回调函数,then有多个就可以注册多个回调函数,但是若多个回调都是异步执行的,那我们要等上一个异步结束后才执行下一个异步,这是时候就需要上一个异步操作完成后,把这个完成状态告诉下一个回调,这样才可以异步串行。为了解决这个问题我们把异步完成状态托管给promise去管理
  479. // 流程:第一步注册:链式调用then函数,每执行一个then函数,返回一个桥梁promise(then函数中的成功回调和失败回调是写入这个promise的回调列表中的,注意成功回调的功能除了执行本身函数外还要更新下一个promise的状态)
  480. // 第二步执行:第一个promise的异步执行完,开始执行第一个promise的回调函数(回调函数又分两步走:第一步:resolvePromise解析回调返回值(如果是promise则说明是异步,就需要继续解析直到不是promise而是一个具体的值),第二步:当回调返回的值是一个具体值而不是promise时,调用第二个proomise的reslove方法将第二个proomise的状态更新为fulfilled,并将第一个promise的回调的值传入p2的回调函数中去执行)
  481. function MyPromise(fn) {
  482. var self = this;
  483. // 成功回调传的参数
  484. self.value = null;
  485. // 失败回调传的参数
  486. self.error = null;
  487. // 当前promise对象的状态
  488. self.status = "pending";
  489. // 存储成功回调列表
  490. self.onFulfilledCallbacks = [];
  491. // 存储失败回调列表
  492. self.onRejectedCallbacks = [];
  493. // 状态改变并执行回调
  494. // 成功
  495. function resolve(value) {
  496. // 判断传入参数是否由MyPromise构造的对象,若是,注册该函数
  497. if (value instanceof MyPromise) {
  498. return value.then(resolve, reject);
  499. }
  500. // 判断
  501. if (self.status === "pending") {
  502. setTimeout(function () {
  503. self.status = "fulfilled";
  504. self.value = value;
  505. // 执行成功回调
  506. // self.onFulfilledCallbacks.forEach(function(callback){callback(self.value)});
  507. // 向下兼容forEach
  508. for (var i = 0; i < self.onFulfilledCallbacks.length; i++) {
  509. self.onFulfilledCallbacks[i](self.value);
  510. }
  511. }, 0)
  512. }
  513. }
  514. // 失败
  515. function reject(error) {
  516. if (self.status === "pending") {
  517. setTimeout(function () {
  518. self.status = "rejected";
  519. self.error = error;
  520. // self.onRejectedCallbacks.forEach(function(callback){callback(self.error)});
  521. for (var i = 0; i < self.onRejectedCallbacks.length; i++) {
  522. self.onRejectedCallbacks[i](self.error);
  523. }
  524. }, 0)
  525. }
  526. }
  527. try {
  528. fn(resolve, reject);
  529. } catch (e) {
  530. reject(e);
  531. }
  532. }
  533. // 解析放回值
  534. // 用来解析回调函数的返回值x,x可能是普通值也可能是个promise对象
  535. // 因为回调函数既可能会返回一个异步的promise也可能会返回一个同步结果,所以我们把直接把回调函数的结果托管给bridgePromise,使用resolvePromise方法来解析回调函数的结果,如果回调函数返回一个promise并且状态还是pending,就在这个promise的then方法中继续解析这个promise reslove传过来的值,如果值还是pending状态的promise就继续解析,直到不是一个异步promise,而是一个正常值就使用bridgePromise的reslove方法将bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入,到此异步操作就衔接上了。
  536. function resolvePromise(bridgepromise, x, resolve, reject) {
  537. // bridgepromise是桥梁promise,x是桥梁promise中注册的成功回调的返回值,resolve和reject是桥梁promise的状态改变函数
  538. // 2.3.1规范,避免循环引用
  539. // 如果成功回调的值又是桥梁promise就返回循环传参的错误(死循环)
  540. if (bridgepromise === x) {
  541. return reject(new TypeError('Circular reference'));
  542. }
  543. var called = false;
  544. // // 如果x是一个promise,则通过递归
  545. // if (x instanceof MyPromise) {
  546. // //如果这个promise是pending状态,就在它的then方法里继续执行resolvePromise解析它的结果,直到返回值不是一个pending状态的promise为止(这里使用了递归的方法)
  547. // if (x.status === "pending") {
  548. // x.then(
  549. // function(y){
  550. // resolvePromise(bridgepromise, y, resolve, reject);
  551. // },
  552. // function(error){
  553. // reject(error);
  554. // }
  555. // );
  556. // }
  557. // else {
  558. // x.then(resolve, reject);
  559. // }
  560. // }
  561. // else
  562. // // 如果x是一个promise,则继续解析它的状态
  563. if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) {
  564. try {
  565. var then = x.then;
  566. if (typeof then === 'function') {
  567. // then方法的指向传入的桥梁promise,也就是说该桥梁promise调用了then方法并传入了成功回调和失败回调
  568. then.call(
  569. x,
  570. // 传入then的成功回调
  571. function (y) {
  572. if (called) return;
  573. called = true;
  574. // 这里重新解析当前的桥梁promise,至于成功回调的返回值传空(这里目的是通过递归持续判断当前桥梁promise的状态)
  575. resolvePromise(bridgepromise, y, resolve, reject);
  576. },
  577. //传入then的失败回调
  578. function (error) {
  579. if (called) return;
  580. called = true;
  581. reject(error);
  582. }
  583. )
  584. }
  585. // 如果then不是一个函数,则以x为值改变promise状态并延长成功回调列表
  586. else {
  587. resolve(x);
  588. }
  589. }
  590. // 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
  591. catch (e) {
  592. if (called) return;
  593. called = true;
  594. reject(e);
  595. }
  596. }
  597. // 如过x不是一个promise,则改变bridgePromise的状态改为fulfilled,并调用onFulfilledCallbacks回调数组中的方法,将该值传入
  598. else {
  599. resolve(x);
  600. }
  601. }
  602. // 注册回调函数
  603. MyPromise.prototype.then = function (onFulfilled, onRejected) {
  604. var self = this;
  605. // 搭建桥梁promise(即调用为then方法后重新返回一个新的promise对象)
  606. var bridgePromise;
  607. // 防止使用者不传成功或失败回调函数,所以成功失败回调都给了默认回调函数
  608. onFulfilled = typeof onFulfilled === "function" ? onFulfilled : function (value) {
  609. return value
  610. };
  611. onRejected = typeof onRejected === "function" ? onRejected : function (error) {
  612. throw error
  613. };
  614. // 如果当前的promise对象是完成状态
  615. // 返回一个新的桥梁promise
  616. if (self.status === "fulfilled") {
  617. return bridgePromise = new MyPromise(function (resolve, reject) {
  618. setTimeout(function () {
  619. try {
  620. // 获取成功回调函数的返回值
  621. var x = onFulfilled(self.value);
  622. // 解析桥梁promise函数
  623. resolvePromise(bridgePromise, x, resolve, reject);
  624. } catch (e) {
  625. reject(e);
  626. }
  627. }, 0);
  628. })
  629. }
  630. // 如果当前的promise对象是拒绝状态
  631. if (self.status === "rejected") {
  632. return bridgePromise = new MyPromise(function (resolve, reject) {
  633. setTimeout(function () {
  634. try {
  635. var x = onRejected(self.error);
  636. resolvePromise(bridgePromise, x, resolve, reject);
  637. } catch (e) {
  638. reject(e);
  639. }
  640. }, 0);
  641. });
  642. }
  643. // 如果当前的promise对象是听候状态,则在当前promise对象的成功回调列表和失败回调列表中注入
  644. if (self.status === "pending") {
  645. return bridgePromise = new MyPromise(function (resolve, reject) {
  646. // 注意回调列表是把整个回调函数和回调解析函数一起注入的!!!!!,所以在执行回调时除运行回调函数还要,解析桥梁promise的状态(有可能桥梁promise中也有promise),解析中改变当前promise的状态,若当前promise的状态为完成状态才继续执行下一个注册好的回调
  647. self.onFulfilledCallbacks.push(function (value) {
  648. try {
  649. var x = onFulfilled(value);
  650. resolvePromise(bridgePromise, x, resolve, reject);
  651. } catch (e) {
  652. reject(e);
  653. }
  654. });
  655. self.onRejectedCallbacks.push(function (error) {
  656. try {
  657. var x = onRejected(error);
  658. resolvePromise(bridgePromise, x, resolve, reject);
  659. } catch (e) {
  660. reject(e);
  661. }
  662. });
  663. });
  664. }
  665. }
  666. MyPromise.prototype.MyCatch = function (onRejected) {
  667. return this.then(null, onRejected);
  668. }
  669. MyPromise.all = function (promises) {
  670. return new MyPromise(function (resolve, reject) {
  671. var result = [];
  672. var count = 0;
  673. for (var i = 0; i < promises.length; i++) {
  674. // (function(i){
  675. // return promises[i].then(function(data) {
  676. // result[i] = data;
  677. // if (++count == promises.length) {
  678. // resolve(result);
  679. // }
  680. // }, function(error) {
  681. // reject(error);
  682. // });
  683. // })(i)
  684. function closeTemp(i) {
  685. return promises[i].then(function (data) {
  686. result[i] = data;
  687. if (++count == promises.length) {
  688. resolve(result);
  689. }
  690. }, function (error) {
  691. reject(error);
  692. });
  693. }
  694. closeTemp(i)
  695. }
  696. });
  697. }
  698. MyPromise.race = function (promises) {
  699. return new MyPromise(function (resolve, reject) {
  700. for (var i = 0; i < promises.length; i++) {
  701. promises[i].then(function (data) {
  702. resolve(data);
  703. }, function (error) {
  704. reject(error);
  705. });
  706. }
  707. });
  708. }
  709. MyPromise.resolve = function (value) {
  710. return new MyPromise(function (resolve) {
  711. resolve(value);
  712. });
  713. }
  714. MyPromise.reject = function (error) {
  715. return new MyPromise(function (resolve, reject) {
  716. reject(error);
  717. });
  718. }
  719. MyPromise.promisify = function (fn) {
  720. return function () {
  721. var args = Array.from(arguments);
  722. return new MyPromise(function (resolve, reject) {
  723. fn.apply(null, args.concat(function (err) {
  724. err ? reject(err) : resolve(arguments[1])
  725. }));
  726. })
  727. }
  728. }
  729. window.MyPromise = MyPromise;
  730. })(window);