理解promise、promise.all、promise.race
文章目录
- promise
- promise.all
- promise.race
- 注意
- 总结
promise
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。 Promise 对象有以下两个特点:
1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
pending: 初始状态,不是成功或失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
怎么理解上述这段概念呢?
简单来说就是promise是处理异步操作的,它有三种状态,初始状态(pending)肯定是必须的,初始状态(pending)也只能变为成功状态(fulfilled)或者失败状态(rejected)的一种,而且状态的改变是不可逆的。
概念性的话不好理解,还是手动操作一下比较好理解。
首先创建一个promise对象:
Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject。
var p = new Promise(function (resolve, reject) {// 异步处理// 处理结束后、调用resolve 或 reject});
只需要知道对象里面是处理异步的、Promise 构造函数的两个参数一个表示成功时候的回调一个表示失败时候的回调就可以了。
举个栗子:
//注:本例中当time为0 的时候就表示调用失败
var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {//当拒绝(失败)时候调用rejectreject('失败了')} else {//当解析(成功)的时候调用resolveresolve('调用' + time + '秒后执行的')}}, time * 1000);})
对于已经实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。
//打印结果:调用2秒后执行的
function runAsync(time) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve('调用' + time + '秒后执行的')}}, time * 1000);})return p}runAsync(2).then(res => {console.log(res)}).catch(err=>{console.log(err)})//本例会在2秒后打印"调用2秒后执行的",因为在promise里面走的是resolve(成功的回调),如果将参数改为0的话就会走reject失败的回调)
看到这里是不是觉得也就那么回事,跟普通函数没什么区别,但是要知道,异步代码是需要等待的,当有多个异步代码要执行时,调用顺序就极为重要。
举个栗子:
我要得到的顺序是:洗漱-上床-睡觉
/*
睡觉
上床
洗漱
*/
打印结果:
function runAsync(time,behavior) {setTimeout(() => {console.log(behavior)}, time * 1000);}runAsync(3,'洗漱')runAsync(2,'上床')runAsync(1,'睡觉')//本例是1秒后打印睡觉,2秒后打印上床,3秒后打印洗漱,因为是同步的方法调用
顺序不对,不过可以通过回调的方式来解决:
/*
洗漱
上床
睡觉
*/function runAsync(time,behavior,callback) {setTimeout(() => {console.log(behavior)callback(behavior)}, time * 1000);}runAsync(3,'洗漱',function(data) {//console.log(data)runAsync(2,'上床',function (data) {//console.log(data)runAsync(1,'睡觉',function (data) {//console.log(data)})})})
//本例是在3秒后打印洗漱,打印完洗漱2后打印上传,打印完上床1秒后打印睡觉
上面的例子是符合要求的,没问题,但是睡觉前还要敷面膜、看电影、撸猫等等操作依次执行的话,就会形成回调地狱,变得累赘且维护起来很差的问题,而且,没有一点可读性!像这样:
runAsync(3, '洗漱', function (data) {//console.log(data)runAsync(2, '上床', function (data) {//console.log(data)runAsync(1, '敷面膜', function (data) {//console.log(data)runAsync(1, '看电影', function (data) {//console.log(data)runAsync(1, '撸猫', function (data) {//console.log(data)runAsync(1, '睡觉', function (data) {//console.log(data)})})})})})})
但是,如果用promise的话,就能避免回调地狱的问题,而且维护起来也比较方便,上面的代码就可以改造一下:
/*
洗漱
上床
睡觉
*/
function runAsync(time,behavior) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve(behavior)}}, time * 1000);})return p}runAsync(3,'洗漱').then(res => {console.log(res)return runAsync(2,'上床')}).then(res => {console.log(res)return runAsync(1,'睡觉')}).then(res => {console.log(res)}).catch(err=>{console.log(err)})//本例是在3秒后打印洗漱,打印完洗漱2后打印上传,打印完上床1秒后打印睡觉
结果是一样的,是不是看起来就清晰了很多呢?
从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。
promise.all
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
简单来说,promise.all就是在所有作为参数的promise对象按顺序执行
完之后再返回所有的值,比如开发中有个组件需要多个请求完成之后再进行渲染,这时候用promise.all就非常nice了
这里要划重点:是按顺序执行的
//["洗漱", "上床", "睡觉"]
function runAsync(time,behavior) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve(behavior)}}, time * 1000);})return p}Promise.all([runAsync(3,'洗漱'), runAsync(2,'上床'), runAsync(1,'睡觉')]).then(res => {console.log(res)}).catch(err=>{console.log(err)})//本例是在3秒后打印["洗漱", "上床", "睡觉"],因为promise.all是等所有异步结果执行完之后再返回结果
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即runAsync(3,‘洗漱’)的结果在前,即便runAsync(3,‘洗漱’)的结果获取的比runAsync(1,‘睡觉’)要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
promise.race
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([runAsync(3,‘洗漱’),runAsync(2,‘上床’), runAsync(1,‘睡觉’)])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
简单来说就是所有异步操作不管成功还是失败,哪个先执行完就返回那个的值,但是好像没用过这个方法。
//睡觉
function runAsync(time,behavior) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve(behavior)}}, time * 1000);})return p}Promise.race([runAsync(3,'洗漱'), runAsync(2,'上床'), runAsync(1,'睡觉')]).then(res => {console.log(res)}).catch(err => {console.log(err)})//本例是在1秒后打印'睡觉',因为promise.race返回最先执行完的结果
注意
不管是promise对象还是promise.all,只要是遇到失败,peomise的状态都会变为rejected,不会执行后面.then(),而是直接走.catch()方法。
promise对象在遇到失败的时候
/*
洗漱
失败了
*/
function runAsync(time,behavior) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve(behavior)}}, time * 1000);})return p}runAsync(3,'洗漱').then(res => {console.log(res)return runAsync(0,'上床')//时间为0的时候会走失败}).then(res => {console.log(res)return runAsync(1,'睡觉')}).then(res => {console.log(res)}).catch(err=>{console.log(err)})
此例是在3秒后打印"洗漱",然后在catch中捕获失败,打印"失败了",而没有走后面的异步操作,是因为遇到错误的时候,会直接走catch(),错误后面的then()不会再执行
promise.all遇到失败的时候
//失败了
function runAsync(time, behavior) {var p = new Promise(function (resolve, reject) {setTimeout(() => {if (time == 0) {reject('失败了')} else {resolve(behavior)}}, time * 1000);})return p}Promise.all([runAsync(3, '洗漱'), runAsync(0, '上床'), runAsync(1, '睡觉')]).then(res => {console.log(res)}).catch(err => {console.log(err)})
//本例中是没有等待直接打印"失败了",是因为promise.all在执行所有异步的时候是一起开始执行的,0秒开始执行的操作失败了,promise的状态已经变为了失败,所以其他的操作也就不会再执行了
promise.race在遇到失败的时候跟promise.all遇到失败的时候是一样的,不同的是promise.race不管成功失败,只返回执行结果最快的那个
总结
- promise就是处理异步的;
- promise.all就是等所有异步执行完再返回结果(按顺序执行所有、按顺序返回所有)
- promise.race就是那个异步先执行完就返回那个结果(只返回最快执行完的那个)
理解promise、promise.all、promise.race相关推荐
- promise的优点promise.all(),promise.race(),promise.allSettled()的原理
Promise也是使用回调函数,只不过是把回调封装在了内部,使用上一直通过 then 方法的链式调用,使得多层的回调嵌套看起来变成了同一层的,书写上以及理解上会更直观和简洁一些.Promise出现之前 ...
- 手写Promise和all、race等方法,附上原理解析
手写一个迷你版的Promise JavaScript 中的 Promise 诞生于 ES2015(ES6),是当下前端开发中特别流行的一种异步操作解决方案,简单实现一个迷你版本帮助深入理解 Promi ...
- Promise:Promise.all、Promise.race、Promise.any的用法及区别
在项目开发过程中经常需要通过异步编程来实现功能,此时就需要我们了解Promise. Promise Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理和更强大. 有了Pro ...
- Promise.all、Promise.allSettled、Promise.any、Promise.race
Promise的实例方法拓展 Promise.all() :方法用于将多个 Promise 实例,包装成一个新的 Promise 实例. Promise.allSettled():用来确定一组异步操作 ...
- Promise.all、Promise.race、Promise.allSettled、Promise.any区别
目录 1.Promise.all 2.Promise.race 3.Promise.allSettled 4.Promise.any 1.Promise.all Promise.all()方法用于将多 ...
- Promise.all()、Promise.allSettled()、Promise.any()、Promise.race()用法与区别
概述 Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值 一个 Promise 必然处于以下几种状态之一: 待定(pending): 初始状态,既没有被兑现,也没有被拒绝. 已兑 ...
- Promise、Promise.all 和Promise.race用法
前段时间的项目中由于大多数是异步请求,所以返回的数据顺序不确定造成了很多数据错误.查了大量的资料总算完成,做个小结. promise基础:resolve,和reject resolve方法:在异步方法 ...
- Promise ,Promise.all 和Promise.race的区别
Promise ,Promise.all 和Promise.race的区别 Promise promise是用来解决异步编程问题的,比传统的回调函数和事件处理方法要更加的合理. promise有三个状 ...
- 多接口调用,使用Promise.all、Promise.race和Promise.any
大纲 1.Promise.all 2.Promise.race 3.Promise.any 1.Promise.all 使用 说明: Promise.all可以将多个Promise实例包装成一个新的P ...
最新文章
- 硬盘IO,SAS,SATA,和HD TUNE
- Castle.ActiveRecord的嵌套事务处理
- 如何实现一个HTML5 RPG游戏引擎——第一章,实现地图类
- 八、linux以模块方式注册设备
- 修改oracle归档目录和大小
- read configuration - shared object - read_comp_configuration_raw
- OSPF次末节区域配置 201
- 一种简单的LRU cache设计 C++
- 阿里6年,我的技术蜕变之路!
- python程序内存分析_python 如何测量运行中的程序内存 -- Valgrind
- 机器学习的实现(语言及库的选择)
- HBase伪分布式搭建
- 基于DWM1000的UWB测距调试(二)
- 分布式数据库核心原理
- 警告: git command could not be found. Please create an alias or add it to your PATH
- 利用云计算来实现业务转型呢,有五个步骤可以遵循
- 便签内容如何从旧手机转到新手机?
- Axure 9 实战案例,基本元件的应用 1,用矩形与标题设计视频封面
- centos7双机搭建_Centos7 Mysql 双机热备实现数据库高可用
- maven 依赖com.google.code.kaptcha