/// (function(global) { "use strict"; /** * PromisePolyfill 构造函数。 * * 模拟 WinJS.Promise 的构造形式: * new PromisePolyfill(init, oncancel) * * @constructor * @param {function(function(any):void,function(any):void,function(any):void):void} pfInit * Promise 初始化函数。 * 该函数在 Promise 创建时立即执行,并接收三个回调: * - complete(value) : 完成 Promise * - error(reason) : 使 Promise 失败 * - progress(value) : 发送进度通知(当前实现为占位) * * @param {function():void} [pfOnCancel] * Promise 取消回调。当调用 promise.cancel() 时执行。 * * @example * var p = new PromisePolyfill( * function (complete, error, progress) { * setTimeout(function () { * complete("done"); * }, 1000); * }, * function () { * console.log("Promise canceled"); * } * ); */ function PromisePolyfill(pfInit, pfOnCancel) { /// /// Promise 初始化函数。 /// 形参签名: /// function( /// complete : function(any):void, /// error : function(any):void, /// progress : function(any):void /// ) /// /// /// Promise 取消回调函数。当 promise.cancel() 被调用时执行。 /// var swState = "pending"; // "fulfilled" | "rejected" var vValue = undefined; var aHandlers = []; function invokeHandlers() { if (swState === "pending") return; for (var i = 0; i < aHandlers.length; i++) { handle(aHandlers[i]); } aHandlers = []; } function handle(hHandler) { if (swState === "pending") { aHandlers.push(hHandler); return; } var pfCallback = swState === "fulfilled" ? hHandler.onFulfilled : hHandler.onRejected; if (!pfCallback) { if (swState === "fulfilled") { hHandler.resolve(vValue); } else { hHandler.reject(vValue); } return; } try { var vResult = pfCallback(vValue); hHandler.resolve(vResult); } catch (ex) { hHandler.reject(ex); } } function resolve(vResult) { try { if (vResult === self) throw new TypeError("A promise cannot be resolved with itself."); if (vResult && (typeof vResult === "object" || typeof vResult === "function")) { var pfThen = vResult.then; if (typeof pfThen === "function") { pfThen.call(vResult, resolve, reject); return; } } swState = "fulfilled"; vValue = vResult; invokeHandlers(); } catch (ex) { reject(ex); } } function reject(vReason) { swState = "rejected"; vValue = vReason; if (typeof PromisePolyfill.onerror === "function") { PromisePolyfill.onerror(vReason); } invokeHandlers(); } // WinJS Promise progress(当前仅占位) function progress(vProgress) { // 当前 polyfill 未实现 progress 传播 } var self = this; try { if (typeof pfInit === "function") { pfInit(resolve, reject, progress); } } catch (ex) { reject(ex); } this.then = function(pfOnFulfilled, pfOnRejected) { return new PromisePolyfill(function(resolve, reject) { handle({ onFulfilled: pfOnFulfilled, onRejected: pfOnRejected, resolve: resolve, reject: reject }); }); }; this["catch"] = function(pfOnRejected) { return this.then(null, pfOnRejected); }; this.done = function(pfOnFulfilled, pfOnRejected) { this.then(pfOnFulfilled, pfOnRejected)["catch"](function(ex) { setTimeout(function() { throw ex; }, 0); }); }; this.cancel = function() { if (pfOnCancel) { try { pfOnCancel(); } catch (ex) {} } reject(new Error("Promise was canceled")); }; this._oncancel = pfOnCancel; this._state = swState; this._value = vValue; } /** * 检查对象是否为 PromisePolyfill 实例 * @param {any} vObj 待检查对象 * @returns {boolean} 是否为 PromisePolyfill 实例 */ PromisePolyfill.is = function(vObj) { return vObj instanceof PromisePolyfill; }; /** * 创建一个已完成的 PromisePolyfill * @param {any} vValue 要返回的值 * @returns {PromisePolyfill} 已完成的 PromisePolyfill */ PromisePolyfill.resolve = function(vValue) { return new PromisePolyfill(function(resolve) { resolve(vValue); }); }; /** * 创建一个已拒绝的 PromisePolyfill * @param {any} vReason 拒绝原因 * @returns {PromisePolyfill} 已拒绝的 PromisePolyfill */ PromisePolyfill.reject = function(vReason) { return new PromisePolyfill(function(resolve, reject) { reject(vReason); }); }; /** * 等待所有 Promise 完成 * @param {Array} aPromises 待处理的 Promise 或普通值数组 * @returns {PromisePolyfill>} 返回包含所有结果的 Promise */ PromisePolyfill.all = function(aPromises) { return new PromisePolyfill(function(resolve, reject) { var nRemaining = aPromises.length; var aResults = new Array(nRemaining); if (nRemaining === 0) resolve([]); function resolver(iIndex) { return function(vValue) { aResults[iIndex] = vValue; nRemaining--; if (nRemaining === 0) resolve(aResults); }; } for (var i = 0; i < aPromises.length; i++) { PromisePolyfill.resolve(aPromises[i]).then(resolver(i), reject); } }); }; /** * 竞速 Promise,谁先完成就返回谁的结果 * @param {Array} aPromises 待处理的 Promise 或普通值数组 * @returns {PromisePolyfill} 最先完成的 Promise 的值 */ PromisePolyfill.race = function(aPromises) { return new PromisePolyfill(function(resolve, reject) { for (var i = 0; i < aPromises.length; i++) { PromisePolyfill.resolve(aPromises[i]).then(resolve, reject); } }); }; /** * Promise join,同 all * @param {Array} aPromises 待处理的 Promise 或普通值数组 * @returns {PromisePolyfill>} 返回包含所有结果的 Promise */ PromisePolyfill.join = function(aPromises) { return PromisePolyfill.all(aPromises); }; /** * 任意 Promise 完成即返回 * @param {Array} aPromises 待处理的 Promise 或普通值数组 * @returns {PromisePolyfill} 最先完成的 Promise 的值,若都失败则 reject 一个错误数组 */ PromisePolyfill.any = function(aPromises) { return new PromisePolyfill(function(resolve, reject) { var nRemaining = aPromises.length; var aErrors = new Array(nRemaining); if (nRemaining === 0) reject(new Error("No promises provided.")); function resolver(vValue) { resolve(vValue); } function rejecter(iIndex) { return function(ex) { aErrors[iIndex] = ex; nRemaining--; if (nRemaining === 0) reject(aErrors); }; } for (var i = 0; i < aPromises.length; i++) { PromisePolyfill.resolve(aPromises[i]).then(resolver, rejecter(i)); } }); }; /** * 给 Promise 添加超时处理 * @param {PromisePolyfill|any} pPromise 要处理的 Promise * @param {number} nMilliseconds 超时时间(毫秒) * @returns {PromisePolyfill} 超时或原 Promise 完成后 resolve/reject */ PromisePolyfill.timeout = function(pPromise, nMilliseconds) { return new PromisePolyfill(function(resolve, reject) { var hTimer = setTimeout(function() { reject(new Error("Promise timed out after " + nMilliseconds + "ms")); }, nMilliseconds); PromisePolyfill.resolve(pPromise).then(function(vValue) { clearTimeout(hTimer); resolve(vValue); }, function(ex) { clearTimeout(hTimer); reject(ex); }); }); }; PromisePolyfill.as = function(vValue) { return PromisePolyfill.resolve(vValue); }; PromisePolyfill.wrap = function(vValue) { return PromisePolyfill.resolve(vValue); }; PromisePolyfill.wrapError = function(vError) { return PromisePolyfill.reject(vError); }; /** * 将数组的每个值依次执行回调 * @param {Array} aValues 数组 * @param {function(any, number): any | PromisePolyfill} pfCallback 回调函数 * @returns {PromisePolyfill>} 所有回调完成的结果数组 */ PromisePolyfill.thenEach = function(aValues, pfCallback) { var aPromises = []; for (var i = 0; i < aValues.length; i++) { aPromises.push(PromisePolyfill.resolve(aValues[i]).then(pfCallback)); } return PromisePolyfill.all(aPromises); }; var hListeners = {}; /** * 全局事件注册 * @param {string} sType 事件类型 * @param {function(any):void} pfHandler 回调函数 */ PromisePolyfill.addEventListener = function(sType, pfHandler) { if (!hListeners[sType]) hListeners[sType] = []; hListeners[sType].push(pfHandler); }; /** * 全局事件移除 * @param {string} sType 事件类型 * @param {function(any):void} pfHandler 回调函数 */ PromisePolyfill.removeEventListener = function(sType, pfHandler) { if (!hListeners[sType]) return; var aList = hListeners[sType]; for (var i = 0; i < aList.length; i++) { if (aList[i] === pfHandler) { aList.splice(i, 1); break; } } }; /** * 全局事件派发 * @param {string} sType 事件类型 * @param {any} vDetail 事件详情 */ PromisePolyfill.dispatchEvent = function(sType, vDetail) { if (!hListeners[sType]) return; var aList = hListeners[sType].slice(); for (var i = 0; i < aList.length; i++) { try { aList[i](vDetail); } catch (ex) {} } }; PromisePolyfill.supportedForProcessing = true; PromisePolyfill.onerror = null; /** * 创建一个在指定毫秒数后完成的 Promise。 * * @param {number} nMilliseconds * 延迟时间(毫秒)。 * * @returns {PromisePolyfill} * 返回 Promise,在延迟结束后完成。 * * @example * WinJS.Promise.delay(500).then(function () { * console.log("500ms elapsed"); * }); */ PromisePolyfill.delay = function(nMilliseconds) { /// /// 延迟时间(毫秒)。 /// /// var hTimer = null; return new PromisePolyfill( function(complete, error, progress) { hTimer = setTimeout(function() { complete(); }, nMilliseconds); }, function() { if (hTimer !== null) { clearTimeout(hTimer); hTimer = null; } } ); }; /** * 创建一个循环执行的 Promise,类似 setInterval。 * * 该 Promise 不会自动完成,除非: * 1. 调用 promise.cancel() * 2. callback 抛出异常 * * @param {function(): (any|PromisePolyfill|WinJS.Promise)} pfCallback * 每次循环执行的回调函数。可以返回 Promise。 * * @param {number} nDelay * 每次执行之间的间隔时间(毫秒)。 * * @returns {PromisePolyfill} * 返回 Promise 对象,可通过 cancel() 停止循环。 * * @example * var p = WinJS.Promise.interval(function () { * console.log("tick"); * }, 1000); * * setTimeout(function () { * p.cancel(); * }, 5000); */ PromisePolyfill.interval = function(pfCallback, nDelay) { /// /// 每次间隔执行的函数。可以返回 Promise。 /// /// /// 执行间隔(毫秒)。 /// /// var bCanceled = false; return new PromisePolyfill( function(complete, error, progress) { function loop() { if (bCanceled) { complete(); return; } try { var vResult = pfCallback(); if (vResult && typeof vResult.then === "function") { vResult.then(waitNext, error); } else { waitNext(); } } catch (ex) { error(ex); } } function waitNext() { if (bCanceled) { complete(); return; } setTimeout(loop, nDelay); } loop(); }, function() { bCanceled = true; } ); }; if (typeof global.Promise !== "undefined") { global.Promise.delay = PromisePolyfill.delay; global.Promise.interval = PromisePolyfill.interval; } if (typeof global.WinJS !== "undefined" && typeof global.WinJS.Promise !== "undefined") { global.WinJS.Promise.delay = PromisePolyfill.delay; global.WinJS.Promise.interval = PromisePolyfill.interval; } if (typeof global.Promise !== "undefined") { var p = global.Promise; if (!p.join) p.join = p.all; if (!p.any) p.any = PromisePolyfill.any; if (!p.timeout) p.timeout = PromisePolyfill.timeout; if (!p.as) p.as = p.resolve; if (!p.wrap) p.wrap = p.resolve; if (!p.wrapError) p.wrapError = p.reject; if (!p.thenEach) p.thenEach = PromisePolyfill.thenEach; if (!p.is) p.is = function(vObj) { return vObj instanceof p; }; if (!p.supportedForProcessing) p.supportedForProcessing = true; if (!p.addEventListener) p.addEventListener = PromisePolyfill.addEventListener; if (!p.removeEventListener) p.removeEventListener = PromisePolyfill.removeEventListener; if (!p.dispatchEvent) p.dispatchEvent = PromisePolyfill.dispatchEvent; if (!p.onerror) p.onerror = null; if (typeof p.prototype.then !== "function") { p.prototype.then = function(onFulfilled, onRejected) { return new p(function(resolve, reject) { this.then(resolve, reject); }).then(onFulfilled, onRejected); }; } if (typeof p.prototype.done !== "function") { p.prototype.done = function(onFulfilled, onRejected) { this.then(onFulfilled, onRejected)["catch"](function(ex) { setTimeout(function() { throw ex; }, 0); }); }; } } if (typeof global.WinJS !== "undefined" && typeof global.WinJS.Promise !== "undefined") { var wp = global.WinJS.Promise; if (!wp.resolve) wp.resolve = function(vValue) { return new wp(function(c) { c(vValue); }); }; if (!wp.reject) wp.reject = function(vReason) { return new wp(function(c, e) { e(vReason); }); }; if (!wp.all) wp.all = function(aPromises) { return wp.join(aPromises); }; if (!wp.race) wp.race = PromisePolyfill.race; global.Promise = wp; if (typeof global.Promise === "undefined") global.Promise = wp; } if (typeof global.Promise === "undefined" && typeof global.WinJS === "undefined") { global.Promise = PromisePolyfill; } })(this);