根据PromiseA+规范手写Promise源码
(function () {
"use strict";
function Promise(executor) {
var self = this;
if (typeof executor !== "function") throw new TypeError("Promise resolver is not a function");
if (!(self instanceof Promise)) throw new TypeError("undefined is not a promise");
self.state = "pending";
self.result = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
var change = function change(state, result) {
if (self.state !== "pending") return;
self.state = state;
self.result = result;
setTimeout(function () {
var callbacks = state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks;
if (callbacks.length > 0) {
for (var i = 0; i < callbacks.length; i++) {
var item = callbacks[i];
if (typeof item === "function") item(self.result);
}
}
});
};
try {
executor(function resolve(value) {
change("fulfilled", value);
}, function reject(reason) {
change("rejected", reason);
});
} catch (err) {
change('rejected', err);
}
}
// 检测是否为promise实例
var isPromise = function isPromise(x) {
if (x !== null && /^(object|function)$/i.test(typeof x)) {
var then;
try {
then = x.then;
} catch (err) {
return false;
}
if (typeof then === "function") return true;
}
return false;
};
// 严格按照PromiseA+规范处理细节
var resolvePromise = function resolvePromise(x, promise, resolve, reject) {
if (x === promise) throw new TypeError("Chaining cycle detected for promise #<Promise>");
if (x !== null && /^(object|function)$/i.test(typeof x)) {
var then;
try {
then = x.then;
} catch (err) {
reject(err);
}
if (typeof then === "function") {
var called = false;
try {
then.call(
x,
function onfulfilled(y) {
if (called) return;
called = true;
resolvePromise(y, promise, resolve, reject);
},
function onrejected(r) {
if (called) return;
called = true;
reject(r);
}
);
} catch (err) {
if (called) return;
reject(err);
}
return;
}
}
resolve(x);
};
// x:执行onfulfilled/onrejected的返回结果
// promise:执行then新返回的实例
var common = function common(callback, result, promise, resolve, reject) {
try {
var x = callback(result);
resolvePromise(x, promise, resolve, reject);
} catch (err) {
reject(err);
}
};
Promise.prototype = {
constructor: Promise,
then: function then(onfulfilled, onrejected) {
var self = this,
promise;
if (typeof onfulfilled !== "function") {
onfulfilled = function onfulfilled(value) {
return value;
};
}
if (typeof onrejected !== "function") {
onrejected = function onrejected(reason) {
throw reason;
};
}
promise = new Promise(function (resolve, reject) {
switch (self.state) {
case "fulfilled":
setTimeout(function () {
common(onfulfilled, self.result, promise, resolve, reject);
});
break;
case "rejected":
setTimeout(function () {
common(onrejected, self.result, promise, resolve, reject);
});
break;
default:
self.onFulfilledCallbacks.push(function (value) {
common(onfulfilled, value, promise, resolve, reject);
});
self.onRejectedCallbacks.push(function (reason) {
common(onrejected, reason, promise, resolve, reject);
});
}
});
return promise;
},
// p1.catch(onrejected) => p1.then(null,onrejected)
catch: function mycatch(onrejected) {
return this.then(null, onrejected);
}
};
Promise.resolve = function resolve(value) {
return new Promise(function (resolve) {
resolve(value);
});
};
Promise.reject = function reject(reason) {
return new Promise(function (_, reject) {
reject(reason);
});
};
Promise.all = function all(promises) {
// Array.isArray
if (!/^\[object Array\]$/i.test(Object.prototype.toString.call(promises))) throw new TypeError("promises must be an array");
var n = 0,
values = [];
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
(function (i) {
var promise = promises[i];
// 如果当前项不是promise实例,我们需要把它变为状态为成功的实例
if (!isPromise(promise)) promise = Promise.resolve(promise);
promise.then(function onfulfilled(value) {
// 都成功,整体实例才是成功的
values[i] = value;
n++;
if (n >= promises.length) resolve(values);
}).catch(function onrejected(reason) {
// 有一个是失败的,整体返回的实例就是失败的
reject(reason);
});
})(i);
}
});
};
// 用来测试自己写的代码是否符合规范的
Promise.deferred = function deferred() {
var result = {};
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
};
/* 暴露API */
if (typeof window !== "undefined") window.Promise = Promise;
if (typeof module === "object" && typeof module.exports === "object") module.exports = Promise;
})();
手写完promise后,可以安装 promises-aplus-tests 插件进行测试
- 配置启动命令
{
"scripts": {
"test": "promises-aplus-tests MyPromise.js"
},
......
}
- 开启测试
npm run test