Promise (1) 如何使用Promise
Promise 也是面试高频问题, 今天我们来看看Promise是什么, 能做什么, 怎么用, 下一期我们自己来模拟一个myPromise
1 Promise 是什么
我们要学会自己给自己提问, 才能加深我们的理解, 首先 Promise 是一个类, 类(class)是ES6 一个新的概念 ,和ES5的构造函数相似,
但不完全一样,
类必须通过 new 操作符 调用 ;
子类通过super() 关键字 来产生this , 在super()之前不能使用this ;
类上有静态属性 和 静态方法 , 并且子类可以继承父类的静态属性和静态方法 ;
Promise 中文 译 为 承诺 ,承诺就是说出来的话不会改变,
Promise 一旦状态发生变化后就不会再变了 ,比如:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(1);
reject('reject');
resolve('resolve')
}, 2000);
}).then((data) => {
console.log(data + '-suc') // 状态为 resolved 触发
}, (err) => {
console.log(err + '-err') // 状态为 rejected 触发
});
结果:两秒后打印 1 , reject-err

由此可见 , 由于reject() 方法 先把 promise 的 状态 由 pendding 变为 rejected ,
所以状态就是rejected , 后面再执行resolve() 方法也没用了, 状态只改变一次。
2 Promise 能做什么
Promise 是为了解决异步回调地狱而出现的, 就是解决那种回调函数中嵌套回调函数的情况。。。。
它可以把这种异步操作以同步操作的流程表达出来, 一个经典的图片加载例子:
function loadImg(src) {
const p = new Promise((resolve, reject) => {
const image = document.createElement('img'); // 创建image标签
image.src = src; // 开始加载
image.onload = () => { // 加载成功的回调
resolve(image); // 成功把image返回
};
image.onerror = () => { // 加载失败的回调
reject(new Error('url not found')); // 失败丢出error
}
});
return p;
}
loadImg('https://timgsa.baidu.com/timg' +
'?image&quality=80&size=b9999_10000&sec=1554215359089&di=173ff60aee0bcc177d33dced2c88b2ed' +
'&imgtype=0&src=http%3A%2F%2Fgss0.baidu.com%2F-fo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%' +
'2Fitem%2F55e736d12f2eb9388d4c2ebad9628535e5dd6f50.jpg').then((data) => {
document.body.appendChild(data); // 成功 把 image 标签 插入 body
data.style.width = '800px';
data.style.height = '600px';
}).catch((err) => {
console.log(err); // 失败打印出错误
});
效果图:

把 图片加载 和 加载成功后的数据处理函数 以 同步操作表达出来 , 而不是把数据处理函数
嵌套在图片加载成功的函数里。
3 Promise 的其他注意事项
1. resolve函数 和 reject 函数 里 都可以传参 , reject里一般传Error的实例,
resolve 里 除了可以传 正常的值 还可以传另一个Promise实例,比如:
const P1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('出错啦'))
}, 4000);
});
const P2 = new Promise ((resolve, reject) => {
setTimeout(() => {
resolve(P1)
}, 1000);
});
P2.then((data) => {
console.log(data);
}, (err) => {
console.log(err)
});
结果: 4 秒 打印出 错误信息

有的小伙伴可能会有疑问,P2 不是执行resolve函数了吗, 为什么打印出的是error 呢 ?
我们重头开始分析, P1 创建 并 立即 执行 , 4秒后 P1 执行 reject () ;
然后 P2 创建 并立即执行 , 1 秒后 执行 resolve();
1 秒钟 到了 , P2 执行 resolve(), 但是 P2 的 resolve 返回的是 P1,
那么后面 P2.then 和 P2 其实就没什么 关系 了 , 它 就和 P1 的状态 绑定 在 一起 了 ,
4 秒钟 到了 , P1 的状态 变成 rejected , P2.then 打印 error
我们再来一个 例子验证 :
const P2 = new Promise ((resolve, reject) => {
setTimeout(() => {
resolve(new Promise((suc, err) => {
}))
}, 1000);
});
P2.then((data) => {
console.log(data);
}, (err) => {
console.log(err)
});
结果 : 控制台没有任何输出
为什么 呢? P2.then 依赖 resolve()里 返回的 Promise 对象 的 状态 ,
而 我 没有 调用 任何 改变 其 状态 的api , 所以 它 的状态 一直是 pendding ,
所以没有输出。
3 Promise 上的静态方法
① Promise.all()
它接受一个由Promise对象组成的数组, 只有数组中所有Promise的状态都为resolved时才会调用成功的回调,
只要有一个状态为rejected, 遇到第一个状态变为rejected时, 就会调用失败的回调;
例子:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 2000);
});
const p2 = new Promise((resolve, reject) => {
resolve(2);
});
const p3 = new Promise((resolve, reject) => {
resolve(3);
});
Promise.all([p1, p2, p3]).then((data) => {
console.log(data); // 2 秒后输出[1, 2, 3]
}).catch((error) => {
console.log(error)
});
两秒后所有状态才变为resolved,然后输出结果。
再看个例子:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 2000);
});
const p2 = new Promise((resolve, reject) => {
reject(2);
});
const p3 = new Promise((resolve, reject) => {
reject(3);
});
Promise.all([p1, p2, p3]).then((data) => {
console.log(data);
}).catch((error) => {
console.log(error) //
});
p2 状态变为rejected后,Promise.all()的状态就变为rejected,并打印出2,
上文我们已经说过, promise的状态只会发生一次改变, 所以即使p3状态再变为rejected,
Promise.all().catch也不会再输出了。
② Promise.race() 和 Promise.all()相反, 只要有一个状态变为resolved, 就会执行then的回调,
并且只打印第一个状态变化返回的值
例子:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(1);
},3000);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(2);
}, 1000)
});
const p3 = new Promise((resolve, reject) => {
reject(3);
});
Promise.race([p1, p2, p3]).then((data) => {
console.log(data + 'suc');
}).catch((error) => {
console.log(error + 'err'); // 3err
});
p3的状态最先发生改变所以打印3err.
Promise.resolve( ) 返回一个状态为resolved的promise对象
Promise.reject() 返回一个状态为rejected 的promise对象
注意事项,链式调用then() 如果不显示return, 隐式返回一个状态为resolved, 值为undefined的promise对象
例子:
const p3 = new Promise((resolve, reject) => {
resolve(3);
}).then((data) => {
console.log(data) //
// return Promise.reject(2);
}).then((data) => {
console.log(data) // undefined
}).then((data) => {
console.log(data) // undefined
});
我们再显示return
const p3 = new Promise((resolve, reject) => {
resolve(3);
}).then((data) => {
console.log(data) //
return Promise.reject(2);
}).then((data) => {
console.log(data) // 不输出
}).then((data) => {
console.log(data) // 不输出
}).catch((err) => {
console.log('err' + err) // err2
});
catch也一样, 隐式返回一个状态为resolved, 值为undefined的promise对象,
下一期我们来研究一下Promise的源码
Promise (1) 如何使用Promise的更多相关文章
- 手写一款符合Promise/A+规范的Promise
手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看.如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的.主要 ...
- 到底什么是promise?有什么用promise怎么用
相信很多人刚接触promise都会晕,但学会后却离不开它,本文详细介绍一下promise,promise解决的问题,帮助新手快速上手 [扫盲] 什么是promise? promise是一种约定,并非一 ...
- 一步一步实现一个Promise A+规范的 Promise
2015年6月,ES2015(即ES6)正式发布后受到了非常多的关注.其中很重要的一点是 Promise 被列为了正式规范. 在此之前很多库都对异步编程/回调地狱实现了类 Promise 的应对方案, ...
- promise核心6 自定义promise
1.定义整体结构(不写实现) 定义一个自己的promise的库 lib(库的简写) 一个js文件.一个js模块(不能用es6 也不能commjs)(用es5模块语法 ) 匿名函数自调用.IIFE ( ...
- promise核心 为什么用promise
为什么要用promise 1.使用纯回调函数 先指定回调函数,再启动异步任务 答 1.指定回调函数的方式更加灵活 可以在执行任务前,中,后 2.支持链式调用,解决回调地狱问题 什么是回调地狱:回调函数 ...
- Promise.resolve( data)与Promise.reject( data )
Promise.resolve( data)与Promise.reject( data ) 常用来生成已经决议失败或成功的promise实例: 1.Promise.reject(data)不管传递的是 ...
- Promise 模式解析:Promise模式与异步及声明式编程
一.构建流程 1.(异步)数据源(请求)的构建:Promise的构建并执行请求: 2.处理流程的构建:then将处理函数保存: 二.处理: 1.请求的响应返回: 2.调用后继处理流程. 三. 1.构建 ...
- Promise个人笔记---【Promise的前世今生】
Promise第一版本 案例是使用Node.js内置的fs模块[就是文件系统模块,负责读写文件.]来模拟异步操作 const fs = require('fs'); function getFileP ...
- 关于defer.promise.then 异步的一个疑问 | 用柯里化做promise | 用递归做promise
疑问:感觉会报错,因为执行到defer.promise.then这时候还没到defer.resolve,因为异步读文件,总归会慢 解答:先执行defer.promise.then,是给callback ...
- 手写符合Promise/A+规范的Promise
const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "r ...
随机推荐
- 解决ubuntu unity下gvim菜单消失的问题
#问题描述:在终端下用gvim 指令打开 gvim就不显示菜单.在不启用unity的桌面环境下用终端打开gvim是有菜单的.从程序菜单中打开gvim是显示菜单的.用sudo打开gvim也可以显示菜单, ...
- Socket.io文字直播聊天室的简单代码
直接上代码吧,被注释掉的主要是调试代码,和技术选型的测试代码 var app = require('express')(); var server = require('http').Server(a ...
- 八爪鱼在哪里设置xpath
分享:35个做好的爬虫规则+160篇图文教程汇总 一般在八爪鱼中,获取网页上某个元素的XPATH有以下几种方式:一.在内置浏览器中点选的操作,八爪鱼自动识别XPATH.但是有时候,自动识别的可能不准确 ...
- API管理平台XXL-API
<API管理平台XXL-API> 一.简介 1.1 概述 XXL-API是一个简洁易用API管理平台,提供API的"管理"."文档"."M ...
- 拿到月薪30K,必选一些Python好书!
论述: Python是所有编程语言中与人工智能最紧密相连的编程语言,阿尔法狗都在使用的 Python 语言. 教育部早在两个月前(自2018年3月起)就以及公布:大学生全国计算机二级考试中必考Pyth ...
- 洛谷 P1129 解题报告
P1129 [ZJOI2007]矩阵游戏 题目描述 小\(Q\)是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个\(N*N\)黑白方阵进行(如同国际象棋一般 ...
- 并发库应用之五 & ReadWriteLock场景应用
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...
- springboot中配置文件application.properties的理解
前言 Spring Boot使用"习惯优于配置"(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来.所以,我们要想把Sprin ...
- SSM-SpringMVC-28:SpringMVC类型转换之自定义日期类型转换器
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 例子很简易,要明白的是思路,话不多说,开讲 上篇博客不是说springmvc默认的日期转换格式是yyyy/M ...
- 在单用户模式下修改CentOS的root密码
我们在使用CentOS的过程中可能会发生忘记root用户密码的情况,本文就从应用的角度简单介绍一下如何在单用户模式下修改root用户的密码. 开启CentOS,进入系统启动菜单 将光标停留在系统开机时 ...