JavaScript 异步编程:Promise 模式原理与简单实现

作者:拾光

时间:2026-10-29

浏览:339

本文深入解析 JavaScript 异步编程中的 Promise 模式,对比回调函数、事件监听等其他方式,阐述 Promise 在提升代码可维护性与优雅性方面的优势。通过手动实现一个简单的 Promise 构造函数,详细拆解 resolve、reject、then 及 callbacks 的工作机制,并结合代码示例演示数据在回调链中的传递过程,帮助开发者理解异步状态管理与链式调用的核心原理。

文章目录

异步编程概述

异步编程是 Web 2.0 时代 JavaScript 开发中广泛采用的技术范式。在实际开发中,异步操作随处可见,最典型的场景包括发送异步 Ajax 请求并绑定回调函数,即在请求响应后执行指定的回调逻辑,且此过程不会阻塞主线程代码的执行。此外,setTimeout 方法也是通过异步执行回调来实现延迟操作的一种常见方式。

若对异步编程概念尚不熟悉,建议参考阮一峰的相关教程。该教程系统介绍了四种主要的异步编程实现方案:

  1. 回调函数(Callback)
  2. 事件监听(Event Listeners)
  3. 发布/订阅模式(Pub/Sub)
  4. Promise 模式

上述四种方案在代码可维护性上呈现逐级递增的趋势,同时理解难度也相应增加。本文重点聚焦于 Promise 模式,旨在深入解析其工作机制。

Promise 模式的核心优势

面对多种异步编程方案,为何选择 Promise?主要原因在于前几种方式(如回调地狱)缺乏灵活性,代码结构不够清晰且难以维护。Promise 的设计初衷正是为了降低异步编程的复杂性,使代码逻辑更加简洁、优雅。

Promise 对象与 then 方法

Promise 的核心在于一个 Promise 对象,该对象提供了一个关键的 then() 方法,用于注册并指定状态变化时的回调函数。例如:


f1().then(f2);

Promise 对象在任何时刻必然处于以下三种状态之一:已完成(resolved)、未完成(unfulfilled/pending)或已拒绝(rejected)。then() 方法的作用是为状态转换指定对应的回调处理函数,并且它总是返回一个新的 Promise 对象,从而支持链式调用。

在 Promise 模式下,数据如何在各个回调函数之间传递?这主要通过 resolve 方法实现。你可以将一个函数的返回值作为参数传递给下一个函数,并将该函数的返回值继续传递给后续函数,形成一条无限延伸的“数据链”。

Promise 代码实现与结构分析

接下来,我们将通过代码来具体实现 Promise 模式:


//constructor
var Promise = function() {
 this.callbacks = [];
}
Promise.prototype = {
 construct: Promise,
 resolve: function(result) {
  this.complete("resolve", result);
 },
 reject: function(result) {
  this.complete("reject", result);
 },
 complete: function(type, result) {
  while (this.callbacks[0]) {
   this.callbacks.shift()[type](result);
  }
 },
 then: function(successHandler, failedHandler) {
  this.callbacks.push({
   resolve: successHandler,
   reject: failedHandler
  });
  return this;
 }
}
// test
var promise = new Promise();
var delay1 = function() {
 setTimeout(function() {
  promise.resolve('数据1');
 }, 1000);
 return promise;
};
var callback1 = function(re) {
 re = re + '数据2';
 console.log(re);
};
delay1().then(callback1)

通过代码分析,我们可以观察到一个简易 Promise 对象构造函数的基本结构:

异步编程概述

  • callbacks:用于存储和管理注册的回调函数。
  • resolve:当请求成功执行时调用的方法。
  • reject:当请求失败时调用的方法。
  • complete:负责执行具体回调逻辑的方法。
  • then:用于绑定成功或失败回调函数的方法。

测试用例与执行流程解析

测试用例如下:


var promise = new Promise();
var delay1 = function() {
 setTimeout(function() {
  promise.resolve('数据1');
 }, 1000);
 return promise;
};
var callback1 = function(re) {
 re = re + '数据2';
 console.log(re);
 promise.resolve(re);
};
var callback2 = function(re) {
 console.log(re + '数据3');
};
delay1().then(callback1).then(callback2);

运行结果:

一秒之后输出:

异步编程概述

逻辑分析:


//第一步
var delay1 = function() {
 setTimeout(function() {
  promise.resolve('数据1');
 }, 1000);
 return promise;
};

该函数利用 setTimeout 方法异步传递数据“1”,并必须返回一个 Promise 对象。


//第二步
var callback1 = function(re) {
 
 re = re + '数据2';
 console.log(re);
 promise.resolve(re);
};

callback1 和 callback2 均是通过 then 方法注册的回调函数。其中,callback1 通过调用 resolve 方法将处理后的数据向下传递。


//第三步
delay1().then(callback1).then(callback2);

delay1() 方法执行完毕后,由于返回了 Promise 对象,因此可以继续调用 then() 方法为 delay1() 内部的 setTimeout 异步操作指定回调函数。由于 then() 方法本身也返回 Promise 对象,因此可以再次调用 then 方法进行链式调用。


//第四步
setTimeout(function() {
 promise.resolve('数据1');
}, 1000);

一秒后,当其他同步代码执行完毕,开始执行异步代码 promise.resolve('数据1');。此时调用 Promise 的 resolve() 方法,指定成功状态,并将“数据1”作为参数传递。


//第五步
resolve: function(result) {
 this.complete("resolve", result);
},
//第六步:循环执行回调,将上一个回调的结果传递给下一个回调
complete: function(type, result) {
 while (this.callbacks[0]) {
  this.callbacks.shift()[type](result);
 }
},

上述流程中,第五步和第六步的执行逻辑相对难以理解,需要重点掌握。

以上即为本文的全部内容,希望能为读者的学习提供有益帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章