## 一、静态方法
  Promise有四个静态方法,分别是resolve()、reject()、all()和race(),本节将着重分析这几个方法的功能和特点。
**1)Promise.resolve()**
  此方法有一个可选的参数,参数的类型会影响它的返回值,具体可分为三种情况(如下所列),其中有两种情况会创建一个新的已处理的Promise实例,还有一种情况会返回这个参数。
  (1)当参数为空或非thenable时,返回一个新的状态为fulfilled的Promise。
  (2)当参数为thenable时,返回一个新的Promise,而它的状态由自身的then()方法控制,具体细节已在之前的thenable一节做过说明。
  (3)当参数为Promise时,将不做修改,直接返回这个Promise。
  下面用一个例子演示这三种情况,注意观察Promise的then()方法的第一个回调函数中接收到的决议结果。
~~~
let tha = {
then(resolve, reject) {
resolve("thenable");
}
};
//参数为空
Promise.resolve().then(function(value) {
console.log(value); //undefined
});
//参数为非thenable
Promise.resolve("string").then(function(value) {
console.log(value); //"string"
});
//参数为thenable
Promise.resolve(tha).then(function(value) {
console.log(value); //"thenable"
});
//参数为Promise
Promise.resolve(new Promise(function(resolve) {
resolve("Promise");
})).then(function(value) {
console.log(value); //"Promise"
});
~~~
**2)Promise.reject()**
  此方法能接收一个参数,表示拒绝理由,它的返回值是一个新的已拒绝的Promise实例。与Promise.resolve()不同,Promise.reject()中所有类型的参数都会原封不动的传递给后续的已拒绝的回调函数,如下代码所示。
~~~
Promise.reject("rejected").catch(function (reason) {
console.log(reason); //"rejected"
});
var p = Promise.resolve();
Promise.reject(p).catch(function (reason) {
reason === p; //true
});
~~~
  第一次调用Promise.reject()的参数是一个字符串,第二次的参数是一个Promise,catch()方法中的回调函数接收到的正是这两个参数。
**3)Promise.all()**
  此方法和接下来要讲解的Promise.race()都可用来监控多个Promise,当它们的状态发生变化时,这两个方法会给出不同的处理方式。
  Promise.all()能接收一个可迭代对象,其中可迭代对象中的成员必须是Promise,如果是字符串、thenable等非Promise的值,那么会自动调用Promise.resolve()转换成Promise。Promise.all()的返回值是一个新的Promise实例,当参数中的成员为空时,其状态为fulfilled;而当参数不为空时,其状态由可迭代对象中的成员决定,具体分为两种情况。
  (1)当可迭代对象中的所有成员都是已完成的Promise时,新的Promise的状态为fulfilled。而各个成员的决议结果会组成一个数组,传递给后续的已完成的回调函数,如下所示。
~~~
var p1 = Promise.resolve(200),
p2 = "fulfilled";
Promise.all([p1, p2]).then(function (value) {
console.log(value); //[200, "fulfilled"]
});
~~~
  (2)当可迭代对象中的成员有一个是已拒绝的Promise时,新的Promise的状态为rejected。并且只会处理到这个已拒绝的成员,接下来的成员都会被忽略,其决议结果会传递给后续的已拒绝的回调函数,如下所示。
~~~
var p1 = Promise.reject("error"),
p2 = "fulfilled";
Promise.all([p1, p2]).catch(function (reason) {
console.log(reason); //"error"
});
~~~
**4)Promise.race()**
  此方法和Promise.all()有很多相似的地方,如下所列。
  (1)能接收一个可迭代对象。
  (2)成员必须是Promise,对于非Promise的值要用Promise.resolve()做转换。
  (3)返回值是一个新的Promise实例。
  新的Promise实例的状态也与方法的参数有关,当参数的成员为空时,其状态为pending;当参数不为空时,其状态是最先被处理的成员的状态,并且此成员的决议结果会传递给后续相应的回调函数,如下代码所示。
~~~
var p1 = new Promise(function(resolve) {
setTimeout(() => {
resolve("fulfilled");
}, 200);
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => {
reject("rejected");
}, 100);
});
Promise.race([p1, p2]).catch(function (reason) {
console.log(reason); //"rejected"
});
~~~
  在p1和p2的执行器中都有一个定时器。由于后者的定时器会先执行,因此通过调用Promise.race(\[p1, p2\])得到的Promise实例,其状态和p2的相同,而p2的决议结果会作为拒绝理由被catch()方法中的回调函数接收。
  根据前面的分析可以得出,Promise.all()能处理一个或多个受监控的Promise,而Promise.race()只能处理其中的一个。
## 二、应用
**1)Promise和生成器**
  用Promise和生成器实现一个运行器,可以取代冗长的Promise链,以一种更直观的方式控制异步,类似于下面这样。
~~~
function load() {
return new Promise(function(resolve, reject) {
resolve("success");
});
}
run(function* () {
var result = yield load();
console.log(result); //"success"
});
~~~
  在load()函数内部,执行的是异步操作,由于处在run运行器中,因此它的决议结果可通过赋值语句直接给到result。这种工作模式完全颠覆了过去用回调函数接收异步操作结果的模式。为此,ES8规范特地引入了两个关键字:async和await,支持这种便捷的工作模式,下面改写上一个示例,用新语法实现相同的功能。
~~~
(async function() {
var result = await load();
console.log(result); //"success"
})();
~~~
  关于run运行器的工作原理和ES8的新语法,限于篇幅原因,此处不再展开说明。
**2)与传统异步操作的组合**
  以往需要用回调函数接收异步处理结果的操作,现在都能改成Promise的模式。以图像加载为例,当图像载入成功时,会触发load事件;而当失败时,会触发error事件。如果后续又有异步操作,那么就只能在这两个事件中处理,但这么一来,就会形成难以控制的回调金字塔。而改用Promise后,就能链式的处理后续的操作,如下所示。
~~~
function preImg(src) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.src = src;
img.onload = function(){
resolve(this);
};
img.onerror = function(){
reject(this);
};
});
};
preImg("img/page.png").then(function(value) {
console.log(value);
});
~~~
*****
> 原文出处:
[博客园-ES6躬行记](https://www.cnblogs.com/strick/category/1372951.html)
[知乎专栏-ES6躬行记](https://zhuanlan.zhihu.com/pwes6)
已建立一个微信前端交流群,如要进群,请先加微信号freedom20180706或扫描下面的二维码,请求中需注明“看云加群”,在通过请求后就会把你拉进来。还搜集整理了一套[面试资料](https://github.com/pwstrick/daily),欢迎浏览。
![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200)
推荐一款前端监控脚本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不仅能监控前端的错误、通信、打印等行为,还能计算各类性能参数,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、扩展运算符和剩余参数
- 3、解构
- 4、模板字面量
- 5、对象字面量的扩展
- 6、Symbol
- 7、代码模块化
- 8、数字
- 9、字符串
- 10、正则表达式
- 11、对象
- 12、数组
- 13、类型化数组
- 14、函数
- 15、箭头函数和尾调用优化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、类
- 21、类的继承
- 22、Promise
- 23、Promise的静态方法和应用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基础实践
- 3、WebRTC视频通话
- 4、Web音视频基础
- CSS进阶
- 1、CSS基础拾遗
- 2、伪类和伪元素
- 3、CSS属性拾遗
- 4、浮动形状
- 5、渐变
- 6、滤镜
- 7、合成
- 8、裁剪和遮罩
- 9、网格布局
- 10、CSS方法论
- 11、管理后台响应式改造
- React
- 1、函数式编程
- 2、JSX
- 3、组件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表单
- 8、样式
- 9、组件通信
- 10、高阶组件
- 11、Redux基础
- 12、Redux中间件
- 13、React Router
- 14、测试框架
- 15、React Hooks
- 16、React源码分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基础
- 4、webpack进阶
- 5、Git
- 6、Fiddler
- 7、自制脚手架
- 8、VSCode插件研发
- 9、WebView中的页面调试方法
- Vue.js
- 1、数据绑定
- 2、指令
- 3、样式和表单
- 4、组件
- 5、组件通信
- 6、内容分发
- 7、渲染函数和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、数据类型
- 2、接口
- 3、类
- 4、泛型
- 5、类型兼容性
- 6、高级类型
- 7、命名空间
- 8、装饰器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系统和网络
- 3、命令行工具
- 4、自建前端监控系统
- 5、定时任务的调试
- 6、自制短链系统
- 7、定时任务的进化史
- 8、通用接口
- 9、微前端实践
- 10、接口日志查询
- 11、E2E测试
- 12、BFF
- 13、MySQL归档
- 14、压力测试
- 15、活动规则引擎
- 16、活动配置化
- 17、UmiJS版本升级
- 18、半吊子的可视化搭建系统
- 19、KOA源码分析(上)
- 20、KOA源码分析(下)
- 21、花10分钟入门Node.js
- 22、Node环境升级日志
- 23、Worker threads
- 24、低代码
- 25、Web自动化测试
- 26、接口拦截和页面回放实验
- 27、接口管理
- 28、Cypress自动化测试实践
- 29、基于Electron的开播助手
- Node.js精进
- 1、模块化
- 2、异步编程
- 3、流
- 4、事件触发器
- 5、HTTP
- 6、文件
- 7、日志
- 8、错误处理
- 9、性能监控(上)
- 10、性能监控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 监控系统
- 1、SDK
- 2、存储和分析
- 3、性能监控
- 4、内存泄漏
- 5、小程序
- 6、较长的白屏时间
- 7、页面奔溃
- 8、shin-monitor源码分析
- 前端性能精进
- 1、优化方法论之测量
- 2、优化方法论之分析
- 3、浏览器之图像
- 4、浏览器之呈现
- 5、浏览器之JavaScript
- 6、网络
- 7、构建
- 前端体验优化
- 1、概述
- 2、基建
- 3、后端
- 4、数据
- 5、后台
- Web优化
- 1、CSS优化
- 2、JavaScript优化
- 3、图像和网络
- 4、用户体验和工具
- 5、网站优化
- 6、优化闭环实践
- 数据结构与算法
- 1、链表
- 2、栈、队列、散列表和位运算
- 3、二叉树
- 4、二分查找
- 5、回溯算法
- 6、贪心算法
- 7、分治算法
- 8、动态规划
- 程序员之路
- 大学
- 2011年
- 2012年
- 2013年
- 2014年
- 项目反思
- 前端基础学习分享
- 2015年
- 再一次项目反思
- 然并卵
- PC网站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端学习之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 日志
- 2020