123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /**
- * Promise对象的内部状态
- *
- * @type {Object}
- */
- var Status = {
- PENDING: 'pending',
- FULLFILLED: 'resolved',
- REJECTED: 'rejected'
- };
- function empty() {}
- /**
- * Promise构造函数
- *
- * @constructor
- * @param {Function} resolver 此Promise对象管理的任务
- */
- function Promise(resolver) {
- // ES6原生的Promise构造函数中,若不通过`new`调用Promise的构造函数,会抛出TypeError异常。此处与其一致
- if (!(this instanceof Promise)) {
- throw new TypeError('TypeError: undefined is not a promise');
- }
- // ES6原生的Promise构造函数中,若无作为函数的resolver参数,会抛出TypeError异常。此处与其一致
- if (typeof resolver !== 'function') {
- throw new TypeError('TypeError: Promise resolver undefined is not a function');
- }
- /**
- * Promise对象内部的状态,初始为`pending`。状态只能由`pending`到`fullfilled`或`rejected`
- *
- * @type {string}
- */
- this._status = Status.PENDING;
- /**
- * Promise对象resolved/rejected后拥有的data/reason
- *
- * - 此处保存此值是为了当一个Promise对象被resolved或rejected后,继续对其调用`then`添加任务,后续处理仍能获得当前Promise的值
- *
- * @type {Mixed}
- */
- this._value;
- /**
- * 当前Promise被resolved/rejected后,需处理的任务
- *
- * - 由于同一个Promise对象可以调用多次`then`方法,以添加多个并行任务,所以此处是一个数组
- *
- * @type {Array.<Function>}
- */
- this._doneCallbacks = [];
- this._failCallbacks = [];
- var promise = this;
- resolver(
- function (data) {
- resolve(promise, data);
- },
- function (reason) {
- reject(promise, reason);
- }
- );
- }
- Promise.prototype = {
- constructor: Promise,
- /**
- * Promise的`then`方法
- *
- * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
- * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- then: function (onResolve, onReject) {
- var promise = new Promise(empty);
- this._doneCallbacks.push(makeCallback(promise, onResolve, 'resolve'));
- this._failCallbacks.push(makeCallback(promise, onReject, 'reject'));
- // 如果在一个已经被fullfilled或rejected的promise上调用then,则需要直接执行通过then注册的回调函数
- run(this);
- return promise;
- },
- /**
- * Promise的`done`方法
- *
- * @param {Function|Mixed} onResolve 当前Promise对象被resolved后,需处理的任务
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- done: function (onResolve) {
- return this.then(onResolve, null);
- },
- /**
- * Promise的`fail`方法
- *
- * @param {Function|Mixed} onReject 当前Promise对象被rejected后,需处理的任务
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- fail: function (onReject) {
- return this.then(null, onReject);
- },
- /**
- * Promise的`catch`方法
- *
- * @param {Function|Mixed} onFail 当前Promise对象被rejected后,需处理的任务
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- catch: function (onFail) {
- return this.then(null, onFail);
- }
- };
- /**
- * 创建一个Promise对象,并用给定值resolve它
- *
- * @param {Mixed} value 用于resolve新创建的Promise对象的值
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- Promise.resolve = function (value) {
- var promise = new Promise(empty);
- resolve(promise, value);
- return promise;
- };
- /**
- * 创建一个Promise对象,并用给定值reject它
- *
- * @param {Mixed} reason 用于reject新创建的Promise对象的值
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- Promise.reject = function (reason) {
- var promise = new Promise(empty);
- reject(promise, reason);
- return promise;
- };
- /**
- * 返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后,
- * 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝
- *
- * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- Promise.race = function (iterable) {
- if (!iterable || !iterable.hasOwnProperty('length')) {
- throw new TypeError('TypeError: Parameter `iterable` must be a iterable object');
- }
- var promise = new Promise(empty);
- for (var i = 0, len = iterable.length; i < len; i++) {
- var iterate = iterable[i];
- if (!(iterate instanceof Promise)) {
- iterate = Promise.resolve(iterate);
- }
- iterate.then(resolveRaceCallback, rejectRaceCallback);
- }
- var settled = false;
- function resolveRaceCallback(data) {
- if (settled) {
- return;
- }
- settled = true;
- resolve(promise, data);
- }
- function rejectRaceCallback(reason) {
- if (settled) {
- return;
- }
- settled = true;
- reject(promise, reason);
- }
- };
- /**
- * 返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决
- *
- * @param {Iterable.<Promise|Mixed>} iterable 一组Promise对象或其它值
- * @return {Promise} 返回一个新的Promise对象,用于链式操作
- */
- Promise.all = function (iterable) {
- if (!iterable || !iterable.hasOwnProperty('length')) {
- throw new TypeError('TypeError: Parameter `iterable` must be a iterable object');
- }
- var promise = new Promise(empty);
- var length = iterable.length;
- for (var i = 0; i < length; i++) {
- var iterate = iterable[i];
- if (!(iterate instanceof Promise)) {
- iterate = Promise.resolve(iterate);
- }
- iterate.then(makeAllCallback(iterate, i, 'resolve'), makeAllCallback(iterate, i, 'reject'));
- }
- var result = [];
- var count = 0;
- function makeAllCallback(iterate, index, action) {
- return function (value) {
- if (action === 'reject') {
- reject(promise, value);
- return;
- }
- result[index] = value;
- if (++count === length) {
- resolve(promise, result);
- }
- }
- }
- };
- /**
- * 返回一个Deferred对象,包含一个新创建的Promise对象,以及`resolve`和`reject`方法
- *
- * @return {Deferred}
- */
- Promise.defer = function () {
- var promise = new Promise(empty);
- return {
- promise: promise,
- resolve: function (data) {
- resolve(promise, data);
- },
- reject: function (reason) {
- reject(promise, reason);
- }
- };
- };
- function run(promise) {
- // `then`方法中也会调用,所以此处仍需做一次判断
- if (promise._status === Status.PENDING) {
- return;
- }
- var value = promise._value;
- var callbacks = promise._status === Status.FULLFILLED
- ? promise._doneCallbacks
- : promise._failCallbacks;
- // Promise需要异步操作
- setTimeout(function () {
- for (var i = 0, len = callbacks.length; i < len; i++) {
- callbacks[i](value);
- }
- });
- // 每个promise只能被执行一次。虽然`_doneCallbacks`和`_failCallbacks`用户不应该直接访问,
- // 但还是可以访问到,保险起见,做清空处理。
- promise._doneCallbacks = [];
- promise._failCallbacks = [];
- }
- function resolve(promise, data) {
- if (promise._status !== Status.PENDING) {
- return;
- }
- promise._status = Status.FULLFILLED;
- promise._value = data;
- run(promise);
- }
- function reject(promise, reason) {
- if (promise._status !== Status.PENDING) {
- return;
- }
- promise._status = Status.REJECTED;
- promise._value = reason;
- run(promise);
- }
- function makeCallback(promise, callback, action) {
- return function promiseCallback(value) {
- // 如果传递了callback,则使用前一个promise传递过来的值作为参数调用callback,
- // 并根据callback的调用结果来处理当前promise
- if (typeof callback === 'function') {
- var x;
- try {
- x = callback(value);
- }
- catch (e) {
- // 如果调用callback时抛出异常,则直接用此异常对象reject当前promise
- reject(promise, e);
- }
- // 如果callback的返回值是当前promise,为避免造成死循环,需要抛出异常
- // 根据Promise+规范,此处应抛出TypeError异常
- if (x === promise) {
- var reason = new TypeError('TypeError: The return value could not be same with the promise');
- reject(promise, reason);
- }
- // 如果返回值是一个Promise对象,则当返回的Promise对象被resolve/reject后,再resolve/reject当前Promise
- else if (x instanceof Promise) {
- x.then(
- function (data) {
- resolve(promise, data);
- },
- function (reason) {
- reject(promise, reason);
- }
- );
- }
- else {
- var then;
- (function resolveThenable(x) {
- // 如果返回的是一个Thenable对象(此处逻辑有点坑,参照Promise+的规范实现)
- if (x && (typeof x === 'object'|| typeof x === 'function')) {
- try {
- then = x.then;
- }
- catch (e) {
- reject(promise, e);
- return;
- }
- if (typeof then === 'function') {
- // 调用Thenable对象的`then`方法时,传递进去的`resolvePromise`和`rejectPromise`方法(及下面的两个匿名方法)
- // 可能会被重复调用。但Promise+规范规定这两个方法有且只能有其中的一个被调用一次,多次调用将被忽略。
- // 此处通过`invoked`来处理重复调用
- var invoked = false;
- try {
- then.call(
- x,
- function (y) {
- if (invoked) {
- return;
- }
- invoked = true;
- // 避免死循环
- if (y === x) {
- throw new TypeError('TypeError: The return value could not be same with the previous thenable object');
- }
- // y仍有可能是thenable对象,递归调用
- resolveThenable(y);
- },
- function (e) {
- if (invoked) {
- return;
- }
- invoked = true;
- reject(promise, e);
- }
- );
- }
- catch (e) {
- // 如果`resolvePromise`和`rejectPromise`方法被调用后,再抛出异常,则忽略异常
- // 否则用异常对象reject此Promise对象
- if (!invoked) {
- reject(promise, e);
- }
- }
- }
- else {
- resolve(promise, x);
- }
- }
- else {
- resolve(promise, x);
- }
- }(x));
- }
- }
- // 如果未传递callback,直接用前一个promise传递过来的值resolve/reject当前Promise对象
- else {
- action === 'resolve'
- ? resolve(promise, value)
- : reject(promise, value);
- }
- };
- }
- module.exports = Promise
|