前端萌新眼中的Promise及使用
一个 Promise 就是一个代表了异步操作最终完成或者失败的对象。这是MDN上关于Promise的解释。在前端开发中,Promise经常被拿来用于处理异步和回调的问题,来规避回调地狱和更好排布异步相关的代码。本篇文章对于Promise以及相关的async/await记录一些自己的理解和体会。
一、Promise的三种状态
从字面的意思理解,Promise即是承诺,既是承诺,那承诺的结果就会有成功和失败两种。而且,我们许下承诺之后不会立即得到结果,在获得成功或是失败的结果之前,我们还需要一点时间来履行这个承诺。Promise的构造其实像极了我们生活中的承诺。

上面这张图就是Promise的结构图。就像我们生活中的承诺一样,Promise也存在三种状态,一种是履行承诺的pending状态,一种是承诺失败时的Rejected状态,再就是承诺成功时Fullfilled状态。
接下来,我们以爱情的名义来承诺一下:
let love = new Promise((resolve, reject) => {
setTimeout(() => { //开始谈恋爱,不过恋爱的结果要以后才知道
let happy = Math.random() >= 0.3 ? true : false
if ( happy ) {
resolve('marry') //恋爱成功,决定结婚
} else {
reject('break') //恋爱失败,决定分手
}
}, 500)
})
love.then(result => {
console.log(result) //处理恋爱成功的回调,result是上面resolve传过来的'marry'
}).catch(result => {
console.log(result) //处理恋爱失败的回调,result是上面reject传过来的'break'
})
上面的代码就是一个简单却完整的Promise的例子。需要特别注意的是,Promise在经过pending状态达到成功或失败状态时就会凝固,即到达成功状态后再也不会失败,失败以后也不会回到成功状态。
所以下面的Promise一定是失败状态的,即便reject后面跟了resolve也没用。正所谓:若爱,请深爱,若弃,请彻底,不要暧昧,伤人伤己。柏拉图这话,说的就是Promise的状态凝固。
let love = new Promise((resolve, reject) => {
reject('break')
resolve('marry')
})
love.then(result => {
console.log(result)
}).catch(result => {
console.log(result)
})
二、Promise的then与catch的几种写法
第一种,最常见的就是上面的写法, 使用then来捕捉resolve状态,使用catch来捕捉reject状态
love.then(result => {
console.log(result)
}).catch(result => {
console.log(result)
})
第二种,不写catch, 把用来捕捉reject状态的函数也写到then里,但是效果和上面一样
love.then(result => {
console.log(result)
}, result => {
console.log(result)
})
第三种,分开写,也是可以的
love.then(result => { //只捕捉和处理成功状态
console.log(result)
})
love.catch(result => { //只捕捉和处理失败状态
console.log(result)
})
三、快速构建一个成功或是失败状态的Promise
Promise自带了两种方法,我们可以利用它们快速构建一个Promise,一个是Promise.resolve(), 用于构建成功状态的Promise;另一个是Promise.reject(),用于构建失败状态的Promise。
let p1 = Promise.resolve('success')
console.log(p1) // 打出来的是 Promise {'success'}
p1.then(result => {
console.log(result) //打出来上面resolve传过来的字符串'success'
})
let p2 = Promise.reject('failed') //上面是一个成功状态Promise,这是一失败状态的Promise
p2.catch(result => {
console.log(result)
})
四、使用Promise.all()来处理一类前端场景
在前端的开发实践中,我们有时会遇到需要发送多个请求并根据请求顺序返回数据的需求,比如,我们要发送a、b、c三个请求,这三个请求返回的数据分别为a1、a2、a3,而我们想要a1、a2、a3按照我们希望的顺序返回。那么,使用Promise.all()方法可以完美的解决这一问题。
假设使用代码如下:
//模拟异步请求的函数
let request = (name, time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
let random = Math.random()
if (random >= 0.2) {
resolve(`${name}成功了`)
} else {
reject(`${name}失败了`)
}
}, time)
})
}
//构建三个Promise实例
let a = request('小明', 1000)
let b = request('小红', 500)
let c = request('小华', 1500)
//使用Promise.all(), 注意它接收的是一个数组作为参数
Promise.all([b,a,c]).then(result => {
console.log(result)
}).catch(result => {
console.log(result)
})
把上面的代码复制下来放到浏览器的调试控制台里多执行几次(第二次执行需要刷新)会发生什么事情呢?你可能猜到了:如果三个请求都成功的话,那么这三个请求所返回的数据就是按照发送请求的顺序排列的,即['小红成功了', '小明成功了', '小华成功了'],而且还是以数组形式返回的;而当其中有请求失败了的话,就只会返回最先失败的结果。
当然,除了这个场景以外,Promise.all()方法还能用于其它地方。比如说,一个页面上有两个请求,只有拿到了这两个请求的数据,页面才会展示,在这之前会显示一个loading加载图。使用Promise.all()也是可以非常简洁的解决这个问题。
五、Promise的链式调用
上面说过的then方法,在每次使用后依然会继续返回一个Promise对象。
let p = Promise.resolve('success')
let response = p.then(result => {
console.log(result)
})
console.log(response) //打出来的response是一个Promise对象
因为then之后返回的还是一个Promise对象,那我们就可以继续then,只不过后面then拿到的参数是上一个then里return的内容,而这个return的内容既可以是普通的字符串、数字等(最后都会被封装成Promise)也可以是自己写的一个Promise对象。
接下来我们接着上面爱的承诺继续写一个链式调用的例子:
let love = new Promise((resolve, reject) => {
setTimeout(() => {
let happy = Math.random() >= 0.3 ? true : false
if ( happy ) {
resolve('marry')
} else {
reject('break')
}
}, 500)
})
let haveChild = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('孩子生了!')
}, 1000)
})
love.then(result => {
console.log(result)
return haveChild // 这里返回一个Promise对象,它的resolve会被下一个then捕捉
}).then(result => {
console.log(result)
return '最后,他们白头偕老!' //这里返回的字符串会传给下一个then
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
这里需要注意的是,在链式调用的最一定要加上一个catch来捕捉链条中可能出现的错误!
六、Promise链式调用可以处理的一个业务场景
当我们需要发送多个请求,而后一个请求总是依赖前一个请求的结果时,Promise的链式操作就可以派上用场了。
我们使用axios来演示,axios本身就使用Promise进行封装,代码如下:
let request = (url) => {
let result = axios.get(url) //result是Promise对象
result.then(response => {
return response
}).catch(error => {
throw new Error('出错了!')
})
}
request(url0).then(response => {
return request(response.data.link)
}).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
上面的代码简单模拟了一下这个过程,有些地方还不完善。
以上就是我对Promise用法的一点理解,很多地方还不完善,如果出错,还请各位朋友们能及时指正!
这是我在掘金上的第一篇文章!感谢观看!
前端萌新眼中的Promise及使用的更多相关文章
- Vue初识:一个前端萌新的总结
一.前言 时隔三年,记得第一次写博客还是2015年了,经过这几年的洗礼,我也从一个后端的小萌新变成现在略懂一点点知识的文青.如今对于前端的东东也算有一知半解,个人能力总的来说,也能够独立开发产品级项目 ...
- hbuilderX创建vue项目之添加router路由(前端萌新)
作为一个刚刚接触前端不久的新人来说,熟悉了一种目录结构或者项目创建方法以后,恨不得一辈子不会变! 可是人要生活,就要工作,既然是打工,当然要满足雇佣者的要求. 今天我来说说 hbuilderX 这个开 ...
- 萌新web前端从零开始(1)——计算机入门
前言:这是一个萌新从零开始的学习之路,与大家分享自己的看法与见解,还请指出错误与遗漏点方便改正. 1.认识计算机. 计算机语言常见的有C,PHP,Ruby,Java,C#,Basic,JS,C++等, ...
- 萌新的IDEA_web开发笔记(未完)
萌新IDEA_web开发笔记 按兴趣自己搞的网页: http://47.94.140.98:8080/ow_web/my_web/web/ 暂时还没做完. 部署在租的服务器上面,背景视频加载可能有点慢 ...
- 萌新--关于vue.js入门及环境搭建
十几天闭关修炼,恶补了html跟css以及JavaScript相应的基础知识,恰巧有个群友准备做开源项目,愿意带着我做,但是要求我必须懂vue.js,所以开始恶补vue.js相关的东西. 在淘宝上买了 ...
- 给萌新HTML5 入门指南
本文由葡萄城技术团队原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. HTML5的发展改变了互联网技术趋势,前端热度依旧不减,所以对于应用开发人员 ...
- 《程序员漫画》| 萌新面试Google
Hello,大家好.今天的更新有点不一样.我给大家带来了一些程序员漫画.这些都是我自己画的哦.希望大家喜欢. 今天的漫画有简约的画风,也有一些写实的风格(漂亮MM总是有特殊待遇).不知道大家喜欢哪种呢 ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(三)(联想)
萌新做词典第三篇,做得不好,还请指正,谢谢大佬! 今天把词典的联想做好了,也是比较low的,还改了之前的查询.遍历等代码. Orz 一样地先放上运行结果: test1 ID : char : 件 w ...
- 萌新笔记——C++里创建 Trie字典树(中文词典)(二)(插入、查找、导入、导出)
萌新做词典第二篇,做得不好,还请指正,谢谢大佬! 做好了插入与遍历功能之后,我发现最基本的查找功能没有实现,同时还希望能够把内存的数据存入文件保存下来,并可以从文件中导入词典.此外,数据的路径是存在配 ...
随机推荐
- Cantor表(模拟)
链接:https://ac.nowcoder.com/acm/contest/1069/I来源:牛客网 题目描述 现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的.他是用下面这一 ...
- PhpMyadmin各版本漏洞合集
1.PhpMyAdmin存在PREGREPLACEEVAL漏洞 影响版本: 3.5.x < 3.5.8.1 and 4.0.0 < 4.0.0-rc3 利用模块: exploit/mult ...
- LeetCode No.91,92,93
No.91 NumDecodings 解码方法 题目 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只 ...
- Qt HWND的句柄与QWidget的转换
QT中用到HWND的句柄在编程中遇到了问题,第三方API用了hwnd类型做形参,但是QT中又没有该类型,可以做如下操作来解决问题. 在.h中先声明: HWND m_hWnd; 再声明 public: ...
- day44-线程
#1.开启线程: from threading import Thread import os def func(): print('func',os.getpid()) t = Thread(tar ...
- IntelliJ IDEA项目断开版本管理解决方案
今天使用idea时打开项目突然发现项目不受svn管理(项目目录依然受svn管理,只是idea脱管了),如遇到可用以下方法: 图片示例: 1. 2. 希望能帮到你
- COMET探索系列一【COMET实践笔记】
这几天在给公司的一个点对点聊天系统升级,之前只是使用简单的ajax轮询方式实现,每5秒钟取一次数据,延时太长,用户体验不是很好,因此打算采用服务器推送技术,故此整理了以下文档,将自己找到的一些资料及心 ...
- EX_KMP算法总结
EX_KMP算法总结 By viv 2014-8-9 0:30 吐槽1:字符串神马的我最讨厌了,但不学不行啊.TAT 吐槽2:写这东西差点错过CF(codeforces). 今天学了ex_kmp,故总 ...
- 新iPhone又要提价,苹果靠什么基业长青?
在股神巴菲特一番煽情言论之后,苹果股价再创新高,达到187.67美元,总市值约为9450亿美元,正大踏步向着1万亿美元市值的目标前进,这是一条科技.经济.财经.社会等领域的头条新闻,遭到全球各界人士的 ...
- win10安装3DSMAX失败,怎么强力卸载删除注册表并重新安装
一些搞设计的朋友在win10系统下安装3DSMAX失败或提示已安装,也有时候想重新安装3DSMAX的时候会出现本电脑windows系统已安装3DSMAX,你要是不留意直接安装3DSMAX,只会安装3D ...