0

0

JS Promise案例代码解析

php中世界最好的语言

php中世界最好的语言

发布时间:2018-05-22 11:47:56

|

2038人浏览过

|

来源于php中文网

原创

这次给大家带来js promise案例代码解析,js promise案例代码解析的注意事项有哪些,下面就是实战案例,一起来看一下。

1、约定

  1. 本文的 demo 代码有些是伪代码,不可以直接执行。

  2. 没有特殊说明,本文所有 demo 都是基于 ES6 规范。

  3. Object.method 代表是静态方法, Object#method 代表的是实例方法。如 Promise#then 代表的是 Promise 的实例方法, Promise.resolve 代表的是 Promise 的静态方法.

2、什么是 Promise?

首先我们来了解 Promise 到底是怎么一回事

Promise 是抽象的异步处理对象,以及对其进行各种操作的组件。我知道这样解释你肯定还是不明白 Promise 是什么东西,你可以把 Promise 理解成一个 容器,里面装着将来才会结束的一个事件的结果,这个事件通常是一个异步操作。

Promise最初被提出是在 E语言中, 它是基于并列/并行处理设计的一种编程语言。Javascript 在 ES6 之后也开始支持 Promise 特性了,用来解决异步操 的问题。这里顺便解释一下什么是 ES6, ECMAScript 是 Javascript 语言的国际标准,Javascript 是 ECMAScript 的有一个实现, 而ES6(全称 ECMAScript 6)是这个标准的一个版本。

3、Javascript 为什么要引入 Promise?

细心的你可能发现了我刚刚说了 Javascript 支持 Promise 实现是为了解决异步操作的问题。谈到异步操作,你可能会说,Javascript 不是可以用回调 函数处理异步操作吗? 原因就是 Promise 是一种更强大的异步处理方式,而且她有统一的 API 和规范,下面分别看看传统处理异步操作和 Promise 处理 异步操作有哪些不同。

使用回调函数处理异步操作:

login("http://www.r9it.com/login.php", function(error, result){
  // 登录失败处理
 if(error){
    throw error;
  }
  // 登录成功时处理
});

Node.js等则规定在JavaScript的回调函数的第一个参数为 Error 对象,这也是它的一个惯例。 像上面这样基于回调函数的异步处理如果统一参数使用规则的话,写法也会很明了。 但是,这也仅是编码规约而已,即使采用不同的写法也不会出错。 而Promise则是把类似的异步处理对象和处理规则进行规范化, 并按照采用统一的接口来编写,而采取规定方法之外的写法都会出错。

使用 Promise 处理异步操作:

var promise = loginByPromise("http://www.r9it.com/login.php"); 
promise.then(function(result){
  // 登录成功时处理
}).catch(function(error){
  // 登录失败时处理
});

通过上面两个 demo 你会发现,有了Promise对象,就可以将异步操作以同步操作的流程表达出来。 这样在处理多个异步操作的时候还可以避免了层层嵌套的回调函数(后面会有演示)。 此外,Promise对象提供统一的接口,必须通过调用 Promise#then Promise#catch 这两个方法来结果,除此之外其他的方法都是不可用的,这样使得异步处理操作更加容易。

4、基本用法

在 ES6 中,可以使用三种办法创建 Promise 实例(对象)

(1). 构造方法

let promies = new Promise((resolve, reject) => {
 resolve(); //异步处理 
});

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

(2). 通过 Promise 实例的方法,Promise#then 方法返回的也是一个 Promise 对象

promise.then(onFulfilled, onRejected);

(3). 通过 Promise 的静态方法,Promise.resolve(),Promise.reject()

var p = Promise.resolve();
p.then(function(value) {
 console.log(value); 
});

4.1 Promise 的执行流程

  1. new Promise构造器之后,会返回一个promise对象;

  2. 为 promise 注册一个事件处理结果的回调函数(resolved)和一个异常处理函数(rejected);

4.2 Promise 的状态

实例化的 Promise 有三个状态:

Fulfilled: has-resolved, 表示成功解决,这时会调用 onFulfilled.

Rejected: has-rejected, 表示解决失败,此时会调用 onRejected.

Pending: unresolve, 表示待解决,既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态.

上面我们提到 Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject.

resolve函数的作用是,将 Promise 对象的状态从 未处理 变成 处理成功 (unresolved => resolved), 在异步操作成功时调用,并将异步操作的结果作为参数传递出去。

reject函数的作用是,将 Promise 对象的状态从 未处理 变成 处理失败 (unresolved => rejected), 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise 实例生成以后,可以用 then 方法和 catch 方法分别指定 resolved 状态和 rejected 状态的回调函数。

以下是 Promise 的状态图

4.3 Promise 的基本特性

【1】 对象的状态不受外界影响 Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。 这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法变。

【2】 一旦状态改变,就不会再变,任何时候都可以得到这个结果 Promise对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。 只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。 如果改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。 这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

例如以下代码, reject 方法是无效的

var promise = new Promise((fuck, reject) => {
 resolve("xxxxx");
 //下面这行代码无效,因为前面 resolve 方法已经将 Promise 的状态改为 resolved 了
 reject(new Error()); 
});
promise.then((value) => { 
 console.log(value);
})

下图是 Promise 的状态处理流程图

5、Promise 的执行顺序

我们知道 Promise 在创建的时候是立即执行的,但是事实证明 Promise 只能执行异步操作,即使在创建 Promise 的时候就立即改变它状态。

var p = new Promise((resolve, reject) => {
 console.log("start Promise");
 resolve("resolved"); 
});
p.then((value) => {
 console.log(value);
}) 
console.log("end Promise");

打印的结果是:

start Promise
end Promise
resolved

或许你会问,这个操作明明是同步的,定义 Promise 里面的代码都被立即执行了,那么回调应该紧接着 resolve 函数执行,那么应该先打印 “resolved” 而不应该先打印 “end Promise”.

这个是 Promise 规范规定的,为了防止同步调用和异步调用同时存在导致的混乱

6、Promise 的链式调用(连贯操作)

前面我们讲过,Promise 的 then 方法以及 catch 方法返回的都是新的 Promise 对象,这样我们可以非常方便的解决嵌套的回调函数的问题, 也可以很方便的实现流程任务。

var p = new Promise(function(resolve, reject) {
  resolve();
});
function taskA() {
  console.log("Task A");
}
function taskB() {
  console.log("Task B");
}
function taskC() {
  console.log("Task C");
}
p.then(taskA())
.then(taskB())
.then(taskC())
.catch(function(error) {
  console.log(error);
});

上面这段代码很方便的实现了从 taskA 到 taskC 的有序执行。

当然你可以把 taskA - taskC 换成任何异步操作,如从后台获取数据:

var getJSON = function(url, param) {
 var promise = new Promise(function(resolve, reject){
 var request = require('ajax-request');
 request({url:url, data: param}, function(err, res, body) {
  if (!err && res.statusCode == 200) {
  resolve(body);
  } else {
  reject(new Error(err));
  }
 });
 });
 return promise;
};
var url = "login.php";
getJSON(url, {id:1}).then(result => {
 console.log(result);
 return getJSON(url, {id:2})
}).then(result => {
 console.log(result);
 return getJSON(url, {id:3});
}).then(result => {
 console.log(result);
}).catch(error => console.log(error));

这样用起来似乎很爽,但是有个问题需要注意,我们说过每个 then() 方法都返回一个新的 Promise 对象,那既然是 Promise 对象,那肯定就有注册 onFulfilled 和 onRejected, 如果某个任务流程的 then() 方法链过长的话,前面的任务抛出异常,会导致后面的任务被跳过。

function taskA() {
  console.log("Task A");
  throw new Error("throw Error @ Task A");
}
function taskB() {
  console.log("Task B");
}
function onRejected(error) {
  console.log(error);
}
function finalTask() {
  console.log("Final Task");
}
var promise = Promise.resolve();
promise
  .then(taskA)
  .then(taskB)
  .catch(onRejected)
  .then(finalTask);

执行的结果是:

Task A
Error: throw Error @ Task A
Final Task

显然, 由于 A 任务抛出异常(执行失败),导致 .then(taskB) 被跳过,直接进入 .catch 异常处理环节。

6.1 promise chain 中如何传递参数

上面我们简单阐述了 Promise 的链式调用,能够非常有效的处理异步的流程任务。

但是在实际的使用场景中,任务之间通常都是有关联的,比如 taskB 需要依赖 taskA 的处理结果来执行,这有点类似 Linux 管道机制。 Promise 中处理这个问题也很简单,那就是在 taskA 中 return 的返回值,会在 taskB 执行时传给它。

function taskA() {
  console.log("Task A");
  return "From Task A";
}
function taskB(value) {
 console.log(value);
  console.log("Task B");
  return "From Task B";
}
function onRejected(error) {
  console.log(error);
}
function finalTask(value) {
 console.log(value);
  console.log("Final Task");
}
var promise = Promise.resolve();
promise
  .then(taskA)
  .then(taskB)
  .catch(onRejected)
  .then(finalTask);

搞定,就这么简单!

6.2 resolve 和 reject 参数

reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例, 比如像上面的 getJSON() 方法一样。

var p1 = new Promise(function (resolve, reject) {
 setTimeout(() => reject(new Error('fail')), 3000)
})
var p2 = new Promise(function (resolve, reject) {
 setTimeout(() => resolve(p1), 1000)
})
p2
 .then(result => console.log(result))
 .catch(error => console.log(error))

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。

如果p1的状态是 pending,那么p2的回调函数就会等待p1的状态改变;

如果p1的状态已经是 resolved 或者 rejected,那么p2的回调函数将会立刻执行。

7、Promise 基本方法

ES6的Promise API提供的方法不是很多,下面介绍一下 Promise 对象常用的几个方法.

7.1 Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

p.then((val) => console.log('fulfilled:', val))
 .catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
 .then(null, (err) => console.log("rejected:", err));

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。 所以通常建议使用 catch 方法去捕获异常,而不要用 then(null, function(error) {}) 的方式,因为这样只能捕获当前 Promise 的异常

p.then(result => {console.log(result)})
 .then(result => {console.log(result)})
 .then(result => {console.log(result)})
 .catch(error => {
  //捕获上面三个 Promise 对象产生的异常
  console.log(error);
 });

跟传统的try/catch代码块不同的是,如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

通俗的说法就是“Promise 会吃掉错误”。

比如下面的代码就出现这种情况

var p = new Promise(function(resolve, reject) {
  // 下面一行会报错,因为x没有声明
  resolve(x + 2);
 });
p.then(() => {console.log("every thing is ok.");});
// 这行代码会正常执行,不会受 Promise 里面报错的影响
console.log("Ok, it's Great.");

7.2 Promise.all()

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。用来处理组合 Promise 的逻辑操作。

var p = Promise.all([p1, p2, p3]);

上面代码 p 的状态由p1、p2、p3决定,分成两种情况。

  1. 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

  2. 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

下面是一个具体的例子

// 生成一个Promise对象的数组
var promises = [1,2,3,4,5,6].map(function (id) {
 return getJSON('/post/' + id + ".json");
});
Promise.all(promises).then(function (posts) {
 // ...
}).catch(function(reason){
 // ...
});

上面代码中,promises 是包含6个 Promise 实例的数组,只有这6个实例的状态都变成 fulfilled,或者其中有一个变为 rejected, 才会调用 Promise.all 方法后面的回调函数。

7.3 Promise.race()

Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。 与 Promise.all 不同的是,只要有一个 promise 对象进入 FulFilled 或者 Rejected 状态的话,Promise.rece 就会继续进行后面的处理

var p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。 Promise.race 方法的参数与 Promise.all 方法一样,如果不是 Promise 实例,就会先调用 Promise.resolve 方法, 将参数转为 Promise 实例,再进一步处理。

下面是一个具体的例子

// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(delay);
    }, delay);
  });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
  timerPromisefy(1),
  timerPromisefy(32),
  timerPromisefy(64),
  timerPromisefy(128)
]).then(function (value) {
  console.log(value);  // => 1
});

7.4 Promise.resolve()

Promise.resolve 方法有2个作用,一个就是前面我们说的,它是通过静态方法创建 Promise 实例的渠道之一, 另一个作用就是将 Thenable 对象转换为 Promise 对象。

那么什么是 Thenable 对象呢?ES6 Promises里提到了Thenable这个概念,简单来说它就是一个非常类似promise的东西。 就像我们有时称具有 .length 方法的非数组对象为 Array like 一样,Thenable 指的是一个具有 .then 方法的对象。

这种将 Thenable对象转换为 Promise 对象的机制要求thenable对象所拥有的 then 方法应该和Promise所拥有的 then 方法具有同样的功能和处理过程, 在将 Thenable 对象转换为 Promise 对象的时候,还会巧妙的利用 Thenable 对象原来具有的 then 方法。

到底什么样的对象能算是 Thenable 的呢,最简单的例子就是 jQuery.ajax(),它的返回值就是 Thenable 的。

将 Thenable 对象转换为 Promise 对象

var promise = Promise.resolve($.ajax('/json/comment.json'));// => promise对象
promise.then(function(value){
  console.log(value);
});

除了上面的方法之外,Promise.resolve方法的参数还有以下三种情况。

(1). 参数是一个 Promise 实例

如果参数是Promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

(2). 参数不是具有then方法的对象,或根本就不是对象

如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为resolved。

var p = Promise.resolve('Hello');
p.then(function (s){
 console.log(s)
});

上面代码生成一个新的Promise对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有then方法), 返回Promise实例的状态从一生成就是resolved,所以回调函数会立即执行。 Promise.resolve方法的参数,会同时传给回调函数。

(3). 不带有任何参数

Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的Promise对象。这个我们在上面讲创建 Promise 实例的三种方法的时候就讲过了

var p = Promise.resolve();
p.then(function () {
 // ...
});

7.5 Promise.reject()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。 需要注意的是,Promise.reject()方法的参数,会原封不动地作为 reject 的理由,变成后续方法的参数。这一点与 Promise.resolve 方法不一致。

const thenable = {
 then(resolve, reject) {
  reject('出错了');
 }
};
Promise.reject(thenable)
.catch(e => {
 console.log(e === thenable)
})
// true

上面代码中,Promise.reject 方法的参数是一个 thenable 对象,执行以后,后面 catch 方法的参数不是 reject 抛出的“出错了”这个字符串, 而是 thenable 对象。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

ShoopD 网上商店系统
ShoopD 网上商店系统

用 php + mysql 驱动的在线商城系统,我们的目标为中国的中小企业及个人提供最简洁,最安全,最高效的在线商城解决方案,使用了自建的会员积分折扣功能,不同的会员组有不同的折扣,让您的商店吸引更多的后续客户。 系统自动加分处理功能,自动处理会员等级,免去人工处理的工作量,让您的商店运作起来更方便省事 采用了自建的直接模板技术,免去了模板解析时间,提高了代码利用效率 独立开发的购物车系统,使用最

下载

js正则相关使用案例分享

vuex与组件联合使用步骤详解

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

16

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

23

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

75

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

95

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

218

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

420

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

168

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

222

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

33

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号