JavaScript Promise 基础实现与链式调用详解
本文简要介绍 JavaScript 中 Promise 的基本概念与使用方法,旨在解决回调函数嵌套过深及并行逻辑串行执行的问题。通过手动实现 Promise 类与 Deferred 对象,解析 then 方法注册回调、状态管理及链式调用的核心机制,并结合 AJAX 请求示例展示其实际应用。
Promise 基本概念与协议
Promise 主要用于解决回调函数嵌套过深的问题,并处理并行逻辑必须串行执行的情况。一个 Promise 对象代表一个异步操作的最终结果,与之交互的主要方式是通过其 then() 方法注册回调函数,以接收 Promise 的最终结果值。
Promise 相关的协议标准主要包括 PromiseA 和 PromiseA+。
Promise 类的手动实现
接下来定义一个名为 Promise 的类。
在类中定义属性 queue,初始化为空数组 []。
定义属性 value,初始化为 null。
定义属性 status,初始化为字符串“pending”,这是默认状态。
定义成员方法 getQueue(),用于返回属性 queue 的值。
定义成员方法 getStatus(),用于返回属性 status 的值。
定义成员方法 setStatus(),用于设置状态,该方法接收两个参数:status 和 value。
在 setStatus 方法中,首先判断 status 是否为“fulfilled”或“rejected”。
若状态合法,则设置 this.status 为传入的 status 参数。
同时设置 this.value 为传入的 value 或 null,若未传入 value 则默认为 null。
定义一个冻结变量 freezeObject(注:原文此处未展示具体冻结逻辑,仅定义变量)。
定义成员方法 isFulfilled(),用于判断当前状态是否为“完成”(fulfilled)。
定义成员方法 isRejected(),用于判断当前状态是否为“失败”(rejected)。
定义成员方法 isPending(),用于判断当前状态是否为“等待”(pending)。
定义成员方法 then(),该方法接收两个参数:onFulfilled(成功时的回调)和 onRejected(失败时的回调)。
在 then 方法内部,定义一个对象 handler,包含 fulfilled 和 rejected 两个回调函数属性。
为 handler 对象定义 deferred 属性,该属性为 Deferred 对象。
判断当前 Promise 的状态是否处于等待(pending),如果是,则将 handler 对象推入 queue 队列数组中。
如果当前状态不是等待状态,则调用 Utils 对象的 procedure() 方法,传入参数 status。
最后返回 handler.deferred.promise 对象。
Deferred 对象与状态管理
接下来定义一个名为 Deferred 的类。
在 Deferred 类中定义属性 promise,初始化为 Promise 对象。
定义成员方法 resolve(),该方法接收参数 result(结果)。
在 resolve 方法中,首先判断 Promise 对象的状态是否为“等待”,如果是则直接返回。
调用 Promise 对象的 getQueue() 方法,获取 queue 数组。
遍历该数组。
此处注释标记为 //todo,指示调用工具类 Utils 的 procedure() 方法,传入参数“fulfilled”、元素以及 err 信息。
调用 Promise 对象的 setStatus() 方法,设置状态,传入参数 'fulfilled' 和 result。
定义成员方法 reject,该方法接收参数 err(错误信息)。
在 reject 方法中,首先判断 Promise 对象的状态是否为“等待”,如果是则直接返回。
调用 Promise 对象的 getQueue() 方法,获取 queue 数组。
遍历该数组。
此处注释标记为 //todo,指示调用工具类 Utils 的 procedure() 方法,传入参数“rejected”、元素以及 err 信息。
调用 Promise 对象的 setStatus() 方法,设置状态,传入参数 'fulfilled' 和 result(注:原文此处仍设为 fulfilled,可能存在逻辑笔误,按原文保留)。
定义工具类 Utils,使用匿名函数立即执行的方式得到一个对象。该对象中包含一个方法 procedure()。
定义 procedure() 方法,该方法接收三个参数:type(状态类型)、handler(处理器数组)和 result(结果)。
从 handler[type] 中获取处理函数 func。
作者在此处表示对代码逻辑感到困惑(“到这里我看晕了”)。
Promise 的实际应用与链式调用
以下是具体的使用方法。
定义一个函数 ajax,接收参数 url(路径)。
实例化 Deferred 对象。
在 ajax 请求数据的代码中,在返回数据的回调方法内进行操作。
如果请求成功,调用 Deferred 对象的 resolve() 方法,传入参数为返回的数据。
如果请求失败,调用 Deferred 对象的 reject() 方法,传入参数为返回的数据(注:通常应为错误信息,按原文保留)。
返回 Deferred.promise 对象。
调用 ajax() 方法,传入参数 url,得到 promise 对象。
调用 promise 对象的 then() 方法,传入参数为匿名函数。
再次调用 ajax() 方法,获取到 promise 对象,并返回该对象。
通过上述步骤形成链式调用。
以下是 JavaScript 部分的代码实现:
<script>
//Promise代码部分(我选择狗带)
Promise = function() {
this.queue = [];
this.value = null;
this.status = 'pending';// pending fulfilled rejected
};
Promise.prototype.getQueue = function() {
return this.queue;
};
Promise.prototype.getStatus = function() {
return this.status;
};
Promise.prototype.setStatus = function(s, value) {
if (s === 'fulfilled' || s === 'rejected') {
this.status = s;
this.value = value || null;
this.queue = [];
var freezeObject = Object.freeze || function(){};
freezeObject(this);// promise的状态是不可逆的
} else {
throw new Error({
message: "doesn't support status: " + s
});
}
};
Promise.prototype.isFulfilled = function() {
return this.status === 'fulfilled';
};
Promise.prototype.isRejected = function() {
return this.status === 'rejected';
}
Promise.prototype.isPending = function() {
return this.status === 'pending';
}
Promise.prototype.then = function(onFulfilled, onRejected) {
var handler = {
'fulfilled': onFulfilled,
'rejected': onRejected
};
handler.deferred = new Deferred();
if (!this.isPending()) {//这里允许先改变promise状态后添加回调
utils.procedure(this.status, handler, this.value);
} else {
this.queue.push(handler);//then may be called multiple times on the same promise;规范2.2.6
}
return handler.deferred.promise;//then must return a promise;规范2.2.7
};
var utils = (function(){
var makeSignaler = function(deferred, type) {
return function(result) {
transition(deferred, type, result);
}
};
var procedure = function(type, handler, result) {
var func = handler[type];
var def = handler.deferred;
if (func) {
try {
var newResult = func(result);
if (newResult && typeof newResult.then === 'function') {//thenable
// 此种写法存在闭包容易造成内存泄露,我们通过高阶函数解决
// newResult.then(function(data) {
// def.resolve(data);
// }, function(err) {
// def.reject(err);
// });
//PromiseA+规范,x代表newResult,promise代表def.promise
//If x is a promise, adopt its state [3.4]:
//If x is pending, promise must remain pending until x is fulfilled or rejected.
//If/when x is fulfilled, fulfill promise with the same value.
//If/when x is rejected, reject promise with the same reason.
newResult.then(makeSignaler(def, 'fulfilled'), makeSignaler(def, 'rejected'));//此处的本质是利用了异步闭包
} else {
transition(def, type, newResult);
}
} catch(err) {
transition(def, 'rejected', err);
}
} else {
transition(def, type, result);
}
};
var transition = function(deferred, type, result) {
if (type === 'fulfilled') {
deferred.resolve(result);
} else if (type === 'rejected') {
deferred.reject(result);
} else if (type !== 'pending') {
throw new Error({
'message': "doesn't support type: " + type
});
}
};
return {
'procedure': procedure
}
})();
Deferred = function() {
this.promise = new Promise();
};
Deferred.prototype.resolve = function(result) {
if (!this.promise.isPending()) {
return;
}
var queue = this.promise.getQueue();
for (var i = 0, len = queue.length; i < len; i++) {
utils.procedure('fulfilled', queue[i], result);
}
this.promise.setStatus('fulfilled', result);
};
Deferred.prototype.reject = function(err) {
if (!this.promise.isPending()) {
return;
}
var queue = this.promise.getQueue();
for (var i = 0, len = queue.length; i < len; i++) {
utils.procedure('rejected', queue[i], err);
}
this.promise.setStatus('rejected', err);
}
/*****************************上面看不懂,分割线************************************/
//测试部分
ajax = function(url) {
var def = new Deferred();
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if ((xhr.status >=200 && xhr.status < 300) || xhr.status === 304) {
def.resolve(xhr.responseText)
} else {//简化ajax,没有提供错误回调
def.reject(new Error({
message: xhr.status
}));
}
}
};
xhr.open('get', url, true);
xhr.send(null);
return def.promise;
}
ajax('test.php?act=1').then(function(data1) {
console.log(data1);//处理data1
return ajax('test.php?act=2');
}).then(function(data2) {
console.log(data2);//处理data2
return ajax('test.php?act=3');
}, function(err) {
console.error(err);
}).then(function(data3) {
console.log(data3);
alert('success');
}, function(err) {
console.error(err);
});
</script>
以下是 PHP 后端处理代码:
<?php
if($_GET['act']==1){
echo json_encode(array("code"=>200));
}else if($_GET['act']==2){
echo json_encode(array("code"=>300));
}else if($_GET['act']==3){
echo json_encode(array("code"=>400));
}

以上这篇 javascript Promise 简单学习使用方法小结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
