promise-zy
Version:
A simple implementation of Promies/A+
599 lines (567 loc) • 25.2 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Promise"] = factory();
else
root["Promise"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
* @Author: zhaoye
* @Date: 2018-04-17 19:02:17
* @Last Modified by: zhaoye
* @Last Modified time: 2018-04-18 21:20:30
* A simple implementation of Promise/A+
*/
// for test
var dontThrow = false;
// specification
// https://promisesaplus.com/#point-56
// 中文:https://segmentfault.com/a/1190000002452115
/**
* 判断一个参数是不是thenable
* @param {any} x
*/
function isThenable(x) {
if (typeof x == 'function' || (typeof x === 'undefined' ? 'undefined' : _typeof(x)) == 'object' && x != null) {
// TODO: 2.3.3.1 将 then 赋为 x.then. [3.5]
// 这条没看懂,不知道实现了没
try {
var then = x.then;
if (then && typeof then == 'function') {
return {
throwed: false,
then: then
};
}
} catch (e) {
return {
throwed: true,
then: e
};
}
}
return {
throwed: false,
then: null
};
}
/**
* 报错
* @param {*} reason
*/
function uncaughtError(r) {
return new Error('Uncaught (in promise) ' + r);
}
/**
* Promise/A+ 实现
*/
var Promise = function () {
/**
* 构造函数
* @param {function} function(resolve, reject) {}
*/
function Promise(cb) {
var _this2 = this;
_classCallCheck(this, Promise);
if (typeof cb != 'function') throw new Error('need 1 argument and it should be a function');
this._decideLock = 'locked';
this._retrivers = [];
// 私有数据,防止被误用或篡改
var __statusTrigger = false;
var __valueTrigger = false;
var __PromiseStatus = 'pending';
var __PromiseValue = void 0;
Object.defineProperties(this, {
_PromiseStatus: {
get: function get() {
return __PromiseStatus;
},
set: function set(value) {
var _this = this;
// you are doing an unilegal set, please use _decide fn
if (this._decideLock == 'locked') return false;
// 2.1
/*
一个Promise必须处在其中之一的状态:pending, fulfilled 或 rejected.
如果是pending状态,则promise:
可以转换到fulfilled或rejected状态。
如果是fulfilled状态,则promise:
不能转换成任何其它状态。
必须有一个值,且这个值不能被改变。
如果是rejected状态,则promise可以:
不能转换成任何其它状态。
必须有一个原因,且这个值不能被改变。
”值不能被改变”指的是其identity不能被改变,而不是指其成员内容不能被改变。
*/
// 2.2.2 如果onFulfilled是一个函数:
/*
它必须在promise fulfilled后调用, 且promise的value为其第一个参数。
它不能在promise fulfilled前调用。
不能被多次调用。
*/
// 2.2.3 如果onRejected是一个函数,
/*
它必须在promise rejected后调用, 且promise的reason为其第一个参数。
它不能在promise rejected前调用。
不能被多次调用。
*/
// the promise status cannot be set again
if (__statusTrigger) {
return false;
}
if (__PromiseStatus == 'pending' && value != 'pending') {
__statusTrigger = true;
__PromiseStatus = value;
if (this._retrivers.length == 0 && this._PromiseStatus == 'rejected') {
if (!dontThrow) {
throw uncaughtError(this._PromiseValue);
}
}
setTimeout(function () {
_this._onStatusChange(value);
});
}
}
},
_PromiseValue: {
get: function get() {
return __PromiseValue;
},
set: function set(value) {
// you are doing an unilegal set, please use _decide fn
if (this._decideLock == 'locked') return false;
// 2.1
if (__valueTrigger) {
// the promise value cannot be set again
return false;
}
__valueTrigger = true;
__PromiseValue = value;
}
}
});
var resolve = function resolve(arg) {
_this2._decide('fufilled', arg);
};
var reject = function reject(arg) {
_this2._decide('rejected', arg);
};
try {
cb(resolve, reject);
} catch (e) {
setTimeout(function () {
_this2._decide('rejected', e);
});
}
}
/**
* promise的状态和value的变更,必须一起进行
* 所以封装decide方法,并且配合一个锁,防止状态和value被decide方法之外的其他方法修改
* @param {string} status
* @param {*} value
*/
_createClass(Promise, [{
key: '_decide',
value: function _decide(status, value) {
this._decideLock = 'unlock';
this._PromiseValue = value;
this._PromiseStatus = status;
this._decideLock = 'locked';
}
/**
* 当promise实例的状态被决定(settled),触发此事件
* @param {string} status
*/
}, {
key: '_onStatusChange',
value: function _onStatusChange(status) {
// 释放之前pending状态时的取值器
// 2.2.6 对于一个promise,它的then方法可以调用多次.
// 当promise fulfilled后,所有onFulfilled都必须按照其注册顺序执行。
// 当promise rejected后,所有onRejected都必须按照其注册顺序执行。
while (this._retrivers.length > 0) {
var retriver = this._retrivers.shift();
try {
var x = void 0;
if (status == 'fufilled') {
if (!retriver.onFufilled) {
// 2.2.7.3 如果 onFulfilled 不是一个函数且promise1已经fulfilled,则promise2必须以promise1的值fulfilled.
x = this._PromiseValue;
} else {
// 2.2.7.1 如果onFulfilled 或 onRejected 返回了值x, 则执行Promise 解析流程[[Resolve]](promise2, x).
// 2.2.5 onFulfilled 和 onRejected 必须被当做函数调用 (i.e. 即函数体内的 this 为undefined). [3.2]
x = retriver.onFufilled.call(undefined, this._PromiseValue);
}
} else if (status == 'rejected') {
if (!retriver.onRejected) {
// 2.2.7.4 如果 onRejected 不是一个函数且promise1已经rejected, 则promise2必须以相同的reason被拒绝.
if (this._PromiseValue instanceof Error) {
throw this._PromiseValue;
} else {
this._reject(retriver.promise2, this._PromiseValue);
continue;
}
} else {
// 2.2.7.1 如果onFulfilled 或 onRejected 返回了值x, 则执行Promise 解析流程[[Resolve]](promise2, x).
// 2.2.5 onFulfilled 和 onRejected 必须被当做函数调用 (i.e. 即函数体内的 this 为undefined). [3.2]
x = retriver.onRejected.call(undefined, this._PromiseValue);
}
}
this._resolve(retriver.promise2, x);
} catch (e) {
// 2.2.7.2 如果onFulfilled 或 onRejected抛出了异常e, 则promise2应当以e为reason被拒绝。
this._reject(retriver.promise2, e);
}
}
}
/**
* 2.3 [[Resolve]](promise, x)
*
* @param {*} promise2 then函数返回的那个promise实例
* @param {*} x 当前的promise实例的执行的结果
*/
}, {
key: '_resolve',
value: function _resolve(promise2, x) {
var _this3 = this;
var _isThenable = isThenable(x),
throwed = _isThenable.throwed,
then = _isThenable.then;
if (throwed) {
throw then;
}
// 2.3.1 如果promise 和 x 指向相同的值, 使用 TypeError做为原因将promise拒绝
if (promise2 == x) {
this._reject(promise2, new TypeError('as [[Resolve]](promise, x) defined, promise === x is wrong'));
}
// 2.3.2 如果 x 是一个promise, 采用其状态 [3.4]:
if (x instanceof Promise) {
// 2.3.2.1 如果x是pending状态,promise必须保持pending走到x fulfilled或rejected.
if (x._PromiseStatus == 'pending') {
// promise2 wait until x is not pending
// and trigger promise2 status
// 为了通过测试用例,各种倒状态
x.then(function (x) {
var _isThenable2 = isThenable(x),
throwed = _isThenable2.throwed,
then = _isThenable2.then;
if (throwed) {
promise2._decide('rejected', then);
} else if (then) {
try {
then.call(x, function (y) {
promise2._decide('fufilled', y);
}, function (r) {
promise2._decide('rejected', r);
});
} catch (e) {
promise2._decide('rejected', e);
}
} else {
promise2._decide('fufilled', x);
}
}, function (r) {
promise2._decide('rejected', r);
});
// 2.3.2.2 如果x是fulfilled状态,将x的值用于fulfill promise
} else if (x._PromiseStatus == 'fufilled') {
// // 递归去解决吧=。=
this._resolve(promise2, x._PromiseValue);
// 2.3.2.3 如果x是rejected状态, 将x的原因用于reject promise
} else if (x._PromiseStatus == 'rejected') {
// 递归去解决吧=。=
if (x._PromiseValue instanceof Promise) {
this._resolve(promise2, x._PromiseValue);
} else {
promise2._decide('rejected', x._PromiseValue);
}
}
// 2.3.3 如果x是一个对象或一个函数
} else if (then) {
// 2.3.3.3 如果 then 是一个函数, 以x为this调用then函数, 且第一个参数是resolvePromise,第二个参数是rejectPromise,且:
// 2.3.3.3.1 当 resolvePromise 被以 y为参数调用, 执行 [[Resolve]](promise, y)
var onceTrigger = false;
var resolvePromise = function resolvePromise(y) {
// 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 都被调用了,或者被调用了多次,则只第一次有效,后面的忽略。
if (!onceTrigger) {
onceTrigger = true;
// [[Resolve]] (promise, y)
try {
_this3._resolve(promise2, y);
} catch (e) {
_this3._reject(promise2, e);
}
}
};
// 2.3.3.3.2 当 rejectPromise 被以 r 为参数调用, 则以r为原因将promise拒绝
var rejectPromise = function rejectPromise(r) {
// 2.3.3.3.3 当 如果 resolvePromise 和 rejectPromise 都被调用了,或者被调用了多次,则只第一次有效,后面的忽略。
if (!onceTrigger) {
onceTrigger = true;
_this3._reject(promise2, r);
}
};
// 2.3.3.3.4 如果在调用then时抛出了异常,则:
try {
then.call(x, resolvePromise, rejectPromise);
} catch (e) {
// 如果 resolvePromise 或 rejectPromise 已经被调用了,则忽略它。
if (!onceTrigger) {
// 否则, 以e为reason将 promise 拒绝。
// 2.3.3.2 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
this._reject(promise2, e);
}
}
// 2.3.3.4 如果 then不是一个函数,则 以x为值fulfill promise
// 2.3.4 如果 x 不是对象也不是函数,则以x为值 fulfill promise
} else {
promise2._decide('fufilled', x);
}
}
/**
*
* @param {*} promise2 then函数返回的那个promise实例
* @param {*} r 当前的promise实例的失败的原因
*/
}, {
key: '_reject',
value: function _reject(promise2, r) {
promise2._decide('rejected', r);
}
/**
* promise实例的取值器
* @param {*} onFufilled 如果promise实例是fufilled状态,执行onFufilled回调
* @param {*} onRejected 如果promise实例是rejected状态,执行onRejected回调
*/
}, {
key: 'then',
value: function then(onFufilled, onRejected) {
var _this4 = this;
// 2.2.1.1
if (typeof onFufilled != 'function') {
onFufilled = null;
}
// 2.2.1.2
if (typeof onRejected != 'function') {
onRejected = null;
}
var promise2 = new Promise(function () {});
// 装弹填充取值器
this._retrivers.push({
onFufilled: onFufilled,
onRejected: onRejected,
promise2: promise2
});
// 2.2.4 onFulfilled 和 onRejected 只允许在 execution context 栈仅包含平台代码时运行. [3.1].
setTimeout(function () {
// 如果已经不是pending的状态了,立即执行取值器的逻辑
if (_this4._PromiseStatus != 'pending') {
_this4._onStatusChange(_this4._PromiseStatus);
}
});
return promise2;
}
/**
* promise实例的取值器,只取失败的值,忽略成功的值
* @param {*} onRejected 如果promise实例是rejected状态,执行onRejected回调
*/
}, {
key: 'catch',
value: function _catch(onRejected) {
return this.then(null, onRejected);
}
}]);
return Promise;
}();
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
// Promise.all(iterable) 方法返回一个 Promise 实例
// 此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);
// 如果参数中 promise 有一个失败(rejected),此实例回调失败(rejecte),失败原因的是第一个失败 promise 的结果。
// in this implementation, it only supports array map set
// *fully tested whit the suites in MDN demo
Promise.all = function () {
var iterable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
if (!iterable) throw new Error('no argument');
if (iterable instanceof Array || iterable instanceof Map || iterable instanceof Set) {} else throw new TypeError('arg type wrong');
return new Promise(function (resolve, reject) {
var results = [];
var failed = false;
var failReason = void 0;
if (iterable.length == 0) resolve(iterable);
iterable.forEach(function (item, index) {
Promise.resolve(item).then(function (value) {
if (failed) return;
results.push({
index: index,
value: value
});
if (results.length == iterable.length) {
resolve(results.sort(function (a, b) {
return a.index > b.index;
}).reduce(function (prev, cur) {
prev.push(cur.value);
return prev;
}, []));
}
}, function (reason) {
// 防止重复发生
if (!failed) {
failed = true;
reject(reason);
}
});
});
});
};
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/race
// Promise.race(iterable) 方法返回一个 promise
// 并伴随着 promise对象解决的返回值或拒绝的错误原因, 只要 iterable 中有一个 promise 对象"解决(resolve)"或"拒绝(reject)"。
// in this implementation, it only supports array map set
// *fully tested whit the suites in MDN demo
Promise.race = function (iterable) {
if (!iterable) throw new Error('no argument');
if (iterable instanceof Array || iterable instanceof Map || iterable instanceof Set) {} else throw new TypeError('arg type wrong');
return new Promise(function (resolve, reject) {
var winner = void 0;
if (iterable.length == 0) resolve(iterable);
iterable.forEach(function (item, index) {
Promise.resolve(item).then(function (value) {
if (!winner) {
winner = value;
resolve(winner);
}
}, function (reason) {
if (!winner) {
winner = reason;
reject(winner);
}
});
});
});
};
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
// Promise.resolve(value)方法返回一个以给定值解析后的Promise对象。
// 但如果这个值是个thenable(即带有then方法),返回的promise会“跟随”这个thenable的对象,
// 采用它的最终状态(指resolved/rejected/pending/settled);如果传入的value本身就是promise对象,
// 则该对象作为Promise.resolve方法的返回值返回;否则以该值为成功状态返回promise对象。
// *fully tested whit the suites in MDN demo
Promise.resolve = function (x) {
var _isThenable3 = isThenable(x),
throwed = _isThenable3.throwed,
then = _isThenable3.then;
if (throwed) {
return new Promise(function (resolve, reject) {
reject(then);
});
}
if (x instanceof Promise) {
return x;
} else if (then) {
return new Promise(function (resolve, reject) {
try {
then.call(x, function (y) {
resolve(y);
}, function (r) {
reject(r);
});
} catch (e) {
reject(e);
}
});
} else {
return new Promise(function (resolve, reject) {
resolve(x);
});
}
};
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
// Promise.reject(reason)方法返回一个用reason拒绝的Promise。
// *fully tested whit the suites in MDN demo
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
});
};
// for test
Promise.dontThrow = function () {
dontThrow = true;
};
module.exports = Promise;
/***/ })
/******/ ]);
});