Appearance
介绍
虽然大部分人开发的时候已经用不上考虑 IE 了,但是我相信还是有像我一样,要求兼容 IE 的需求
我也经常写 ES6,其中 Promise 用的也是最多的。所以在学习 Promises/A+
标准后,特地使用 ES5 语法编写了一套 Promise,通过了 Promises/A+
检查
实现
支持 Promise.all,Promise.resolve,Promise.defer,finally
其他的功能有兴趣的可以自己尝试补充
javascript
var PENDING = 'PENDING';
var RESOLVE = 'RESOLVE';
var REJECT = 'REJECT';
var isPromise = function (arg) {
if ((typeof arg === 'object' && arg !== null) || typeof arg === 'function') {
if (typeof arg.then === 'function') {
return true;
} else {
return false;
}
} else {
return false;
}
};
var resolvePromise = function (promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
var called;
try {
var then = x.then;
if (typeof then === 'function') {
then.call(
x,
function (y) {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
function (r) {
if (called) return;
called = true;
reject(r);
}
);
} else {
if (called) return;
called = true;
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(x);
}
};
function Promise(execute) {
// 如果不是function,则报错
if (typeof execute !== 'function') {
throw Error('Promise resolver undefined is not a function');
}
var _self = this;
this.status = PENDING;
this.onFulfilledCbs = [];
this.onRejectedCbs = [];
this.resolve = function (value) {
if (_self.status === PENDING) {
_self.status = RESOLVE;
_self.value = value;
_self.onFulfilledCbs.forEach(function (item) {
return item();
});
_self.onFulfilledCbs.length = 0;
_self.onRejectedCbs.length = 0;
}
};
this.reject = function (value) {
if (_self.status === PENDING) {
_self.status = REJECT;
_self.value = value;
_self.onRejectedCbs.forEach(function (item) {
return item();
});
_self.onFulfilledCbs.length = 0;
_self.onRejectedCbs.length = 0;
}
};
try {
execute(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
var _self = this;
onFulfilled =
typeof onFulfilled === 'function'
? onFulfilled
: function (data) {
return data;
};
onRejected =
typeof onRejected === 'function'
? onRejected
: function (err) {
throw err;
};
var promise2 = new Promise(function (resolve, reject) {
if (_self.status === RESOLVE) {
setTimeout(function () {
try {
var x = onFulfilled(_self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (_self.status === REJECT) {
setTimeout(function () {
try {
var x = onRejected(_self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (_self.status === PENDING) {
_self.onFulfilledCbs.push(function () {
setTimeout(function () {
try {
var x = onFulfilled(_self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
_self.onRejectedCbs.push(function () {
setTimeout(function () {
try {
var x = onRejected(_self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
};
Promise.prototype.finally = function (cb) {
return this.then(
function (data) {
return Promise.resolve(cb(data)).then(function () {
return data;
});
},
function (err) {
return Promise.resolve(cb(data)).then(function () {
throw err;
});
}
);
};
Promise.resolve = function (arg) {
if (isPromise(arg)) {
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
resolvePromise(promise2, arg, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
return promise2;
} else {
return new Promise(function (resolve, reject) {
resolve(arg);
});
}
};
Promise.defer = Promise.deferred = function () {
var dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
Promise.all = function (values) {
return new Promise(function (resolve, reject) {
var arr = [];
var index = 0;
var pushIn = function (key, data) {
arr[key] = data;
index++;
if (index === values.length) resolve(arr);
};
for (var i = 0; i < values.length; i++) {
(function (i) {
var item = values[i];
Promise.resolve(item).then(function (data) {
pushIn(i, data);
});
})(i);
}
});
};
Promise.author = 'LXH';