参考文档:
本实例简易实现了 angularJS $q 的服务部分内容
(function(window) {
// Q.defer() 返回一个 Deferred 对象
window.Q = {
"defer": function() {
return new Deferred();
}
};
/**
* Deferred 对象有三个方法
* resolve 成功 改变 promise 状态为 fulfilled
* reject 失败 改变 promise 状态为 rejected
* notify 进度 不改变 promise 状态
*/
function Deferred() {
this.promise = new Promise();
}
Deferred.prototype.resolve = function(value) {
if (!this.promise.isPending()) {
return;
}
this.promise.getQueue().forEach(function(queue) {
procedure("fulfilled", queue, value);
});
this.promise.setStatus("fulfilled", value);
};
Deferred.prototype.reject = function(value) {
if (!this.promise.isPending()) {
return;
}
this.promise.getQueue().forEach(function(queue) {
procedure("rejected", queue, value);
});
this.promise.setStatus("rejected", value);
};
Deferred.prototype.notify = function(value) {
if (!this.promise.isPending()) {
return;
}
this.promise.getQueue().forEach(function(queue) {
procedure("pending", queue, value);
});
};
/**
* 每个promise都有三个状态:pending(默认)、fulfilled(完成)、rejected(失败)
* 默认状态可以转变为完成态或失败态,完成态与失败态之间无法相互转换,
* 转变的过程是不可逆的,转变一旦完成promise对象就不能被修改。
*/
function Promise() {
this.state = "pending";
this.queue = [];
this.value = null;
}
Promise.prototype.isPending = function() {
return "pending" === this.state;
};
Promise.prototype.setStatus = function(state, value) {
this.state = state;
this.value = value || null;
this.queue = [];
// 冻结对象自身的所有属性 promise 的状态是不可逆的
Object.freeze(this);
};
Promise.prototype.getQueue = function() {
return this.queue;
};
Promise.prototype.then = function(resolveFn, rejectFn, notifyFn) {
var handler = {
"fulfilled": resolveFn,
"rejected": rejectFn,
"pending": notifyFn
};
if (!this.isPending()) {
// 允许先改变promise状态后添加回调
procedure(this.state, handler, this.value);
} else {
this.queue.push(handler);
}
return this;
};
function procedure(type, handler, value) {
var func = handler[type];
if (isFunction(func)) {
func(value);
}
}
function isFunction(obj) {
return "[object Function]" === Object.prototype.toString.call(obj);
}
})(window);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./src/promise.js"></script>
<script>
function resolveFn() {
var defer = window.Q.defer();
setTimeout(function () {
defer.resolve("hi");
}, 2000);
return defer.promise;
}
var resolve = resolveFn();
resolve.then(function (value) {
console.log(value + " " + new Date());
});
setTimeout(function () {
resolve.then(function (value) {
console.log(value + " " + new Date());
});
}, 5000);
function rejectFn() {
var defer = window.Q.defer();
setTimeout(function () {
defer.reject("hi");
}, 2000);
return defer.promise;
}
rejectFn().then(function () {}, function (value) {
console.log(value + " " + new Date());
});
</script>
</body>
</html>