快速入门上手JavaScript中的Promise
当我还是一个小白的时候,我翻了很多关于Promise
介绍的文档,我一直没能理解所谓解决异步操作的痛点是什么意思
直到我翻了谷歌第一页的所有中文文档我才有所顿悟,其实从他的英文字面意思理解最为简单粗暴
这就是一个承诺,相当于在代码中提供一个在任何时候承诺之后要做什么事的方式,这个承诺可能会兑现也可能无法兑现,当然也可能在兑现的过程中
用这个来替代我们曾经需要写的回调函数,可以避免JavaScript程序中的回调地狱
所以先不去学习的语法,从另一个方式先理解,希望可以帮助你更好的学习或上手Promise
什么是Promise?
Promise
是异步编程的一种解决方案,可以替代传统的解决方案,比如回调函数和事件
其在ES6中统一了用法,并提供了原生的Promise对象
,Promise对象
表示异步操作的最终完成(或失败)及其结果值
作为对象,Promise
有以下两个特点:
- 对象的状态不受外界影响
- 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,
这也是Promise
这个名字的由来,它的英语意思就是承诺,表示其他手段无法改变
- 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,
- 一旦状态改变了就不会在变,也就是说任何时候Promise都只有一种状态
pending
:初始状态,不是成功或失败状态;
fulfilled(resolved)
:操作成功完成状态;
rejected
:操作失败状态Promise对象
的状态改变,只有两种可能:从Pending
变为Resolved
和从Pending
变为Rejected
,
只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,
就算改变已经发生了,你再对Promise对象
添加回调函数,也会立即得到这个结果,
这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的
Promise的创建和用途
- 构造函数接受一个名为
executor
的函数,此执行函数接受两个f函数
参数,resolve
和reject
。
new Promise( /* executor */ function(resolve, reject { ... }) );
- Promise通常用于阻塞代码和异步操作,其中包括文件调用,API调用,DB调用,IO调用等等
- 这些异步操作的启动发生在执行函数中,如果异步操作成功,则通过
promise
的创建者调用resolve()
函数返回预期结果,
同样,如果出现意外错误,则通过调用reject()
函数传递错误具体信息 - 由于
promise
会立即执行,我们无法检查promise
的初始状态,所以创建一个需要时间执行的promise
最简单的方式就是
使用setTimeOut()
函数,通过浏览器控制台的输出可以直观看到之前所说的状态,以及他的变化过程
var promiseFir = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({
message: '与大家分享知识很开心!',
code: 200
});
}, 2000)
})
console.log(promiseFir);
setTimeout(function() {
console.log(promiseFir);
}, 2000)
Promise的方法
- 3种原型方法
// 用一个小故事举例,你是一个上学的孩子,你问你的妈妈要一个电话。她说: 这个月底我要买一部手机
var momsPromise = new Promise(function(resolve, reject) {
momsSavings = 20000; // 因为妈妈没有足够储蓄所以无法买到礼物
// momsSavings = 200000; // 如果妈妈有足够的储蓄就可以买到礼物
priceOfPhone = 60000;
if (momsSavings > priceOfPhone) {
resolve({
brand: "iphone",
model: "6s"
});
} else {
reject("我们没有足够的储蓄,让我们多存点钱吧。");
}
});
momsPromise.then(function(value) {
console.log("哇,我得到这个电话作为礼物 ", JSON.stringify(value));
});
momsPromise.catch(function(reason) {
console.log("妈妈不能给我买电话,因为 ", reason);
});
momsPromise.finally(function() {
console.log(
"不管妈妈能不能给我买个电话,我仍然爱她"
);
});
Promise.prototype.then(onFulfilled, onRejected) 链式操作
Promise.prototype.then()
方法返回的是一个新的Promise对象
,因此可以采用链式写法Promise.prototype.then()
方法带有以下三个参数:成功回调,失败回调,前进回调,一般情况下只需要实现第一个,后面是可选的
function ptFir() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法1执行');
resolve('方法1执行完毕');
}, 2000)
})
}
function ptSec() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法2执行');
resolve('方法2执行完毕');
}, 1000)
})
}
function ptThi() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法3执行');
resolve('方法3执行完毕');
}, 3000)
})
}
ptFir().then(function(data) {
console.log('第一个回调:' + data);
return ptSec();
}).then(function(data) {
console.log('第二个回调:' + data);
return ptThi();
}).then(function(data) {
console.log('第三个回调:' + data);
return '还没完?该结束了吧!';
}).then(function(data) {
console.log(data);
})
Promise.prototype.catch(onRejected) 捕捉错误
Promise.prototype.catch()
方法是Promise.prototype.then(null, rejection)
的别名,用于指定发生错误时的回调函数Promise对象
的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止,也就是说,错误总是会被下一个catch
语句捕获
promise().then(function(data) {
// todo something
}).catch(function(err) {
// 处理上个回调函数的错误
})
Promise.prototype.finally(onFinally) 最终操作
不管promise对象
最后的状态,在执行完.then
或catch
指定的回调函数以后,都会执行finally
方法指定的回调函数
promise().then(function(data) {
// todo something
}).catch(function(err) {
// 处理上个回调函数的错误
}).finally(function(result) {
// 处理then/catch之后必须执行的操作
})
Promise.resolve() / Promise.reject()
- 这两个是帮助方法或快捷方式,它们可以帮助您轻松创建
resolve
和reject
方法 - 需要注意的是:如果
Promise.resolve()
方法的参数,
不是具有.then()
方法的对象(又称thenable对象
),则返回一个新的Promise对象
,且它的状态为fulfilled
;
如果Promise.resolve
方法的参数是一个Promise对象
的实例,则会被原封不动地返回 Promise.reject()
方法同上
var promise = Promise.resolve('Hello,这里是执行成功的内容!');
// var promise = Promise.reject('出错了,这里是被发现的错误!'); // 成功和失败只会有一种状态哦
promise.then(function(data) {
console.log(data)
});
promise.catch(function(err) {
console.log(err)
});
Promise.all()
- 当你处理多个
promise
时,最好先创建一个promise数组
,然后对这些promise集
执行必要的操作 Promise.all(iterable) 方法
返回一个Promise实例
,此实例在iterable参数
内所有的promise
- 都完成(resolved)或参数中不包含
promise
时回调完成(resolve) - 如果参数中
promise
有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败promise
的结果 - 注意!!!这里的异步操作是并行执行的,等到它们都执行完后才会进到
then()
里面,
并且all()
方法会把所有异步操作的结果放进一个数组中传给then()
- 下面的示例需要说明的内容
- 只有3个方法的状态都变成
fulfilled
,p的状态才会变成fulfilled
,此时3个方法的返回值组成一个数组,传递给p的回调函数 - 只要3个方法之中有一个被
rejected
,p的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p的回调函数
- 只有3个方法的状态都变成
function ptFir() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法1执行');
resolve('方法1执行完毕');
}, 2000)
})
}
function ptSec() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法2执行');
resolve('方法2执行完毕');
}, 1000)
})
}
function ptThi() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('方法3执行');
resolve('方法3执行完毕');
}, 3000)
})
}
Promise.all([ptFir(), ptSec(), ptThi()]).then(function(data) {
console.log(data);
console.log({}.toString.call(data));
})
Promise.race()
Promise.race(iterable)
方法返回一个promise
,一旦迭代器中的某个promise
解决或拒绝,返回的promise
就会解决或拒绝all()
方法的效果实际上是「谁跑的慢,以谁为准执行回调」 ,
那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race()
方法,这个词本来就是赛跑的意思- 这个
race()
方法有什么用呢?使用场景还是很多的,比如我们可以用race()
给某个异步请求设置超时时间,
并且在超时后执行相应的操作
// ptFir(), ptSec(), ptThi() 同上
Promise.all([ptFir(), ptSec(), ptThi()]).then(function(data) {
console.log(data);
console.log({}.toString.call(data));
})
使用Promise的一些经验法则
- 进行异步操作或使用阻塞代码时,请使用
Promise
- 为了代码的可读性,
resolve()
方法对待.then()
,reject()
方法对应.catch()
- 确保同时写入
.catch()
和.then()
方法来实现所有的promise
- 如果在这两种情况下都需要做一些事情,请使用
.finally()
- 我们只有一次改变每个
promise (单一原则)
- 我们可以在一个
promise
中添加多个处理程序 Promise对象
中所有方法的返回类型,无论是静态方法还是原型方法,都是Promise
- 在
all()
方法中,无论哪个promise
首先未完成,promise
的顺序都保持在值变量中
参考文档一 ———— 彻底理解Javascript 中的 Promise
参考文档二 ———— 通俗浅显的理解Promise中的then
参考文档三 ———— 理解 Javascript 中的 Promise
参考文档四 ———— JavaScript Promise 对象
我是 fx67ll.com,如果您发现本文有什么错误,欢迎在评论区讨论指正,感谢您的阅读!
如果您喜欢这篇文章,欢迎访问我的 本文github仓库地址,为我点一颗Star,Thanks~
转发请注明参考文章地址,非常感谢!!!
快速入门上手JavaScript中的Promise的更多相关文章
- webpack快速入门——处理HTML中的图片
在webpack中是不喜欢你使用标签<img>来引入图片的,但是我们作前端的人特别热衷于这种写法, 国人也为此开发了一个:html-withimg-loader.他可以很好的处理我们在ht ...
- javascript中的promise和deferred:实践(二)
javascript中的promise和deferred:实践(二) 介绍: 在第一节呢,我花了大量的时间来介绍promises和deferreds的理论.现在呢,我们来看看jquery中的promi ...
- JavaScript中的Promise【期约】[未完成]
JavaScript中的Promise[期约] 期约主要有两大用途 首先是抽象地表示一个异步操作.期约的状态代表期约是否完成. 比如,假设期约要向服务器发送一个 HTTP 请求.请求返回 200~29 ...
- Vue.js——60分钟快速入门 开发· webpack 中文文档
转载于:http://www.cnblogs.com/keepfool/p/5619070.html http://www.css88.com/doc/webpack2/guides/get-star ...
- 通过一道笔试题浅谈javascript中的promise对象
因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...
- Javascript中的Promise
Promise定义 Promise是CommonJs的规范之一,包含resolve,reject,done,fail,then等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套.异步在web开发中 ...
- R语言快速入门上手
导言: 较早之前就听说R是一门便捷的数据分析工具,但由于课程设计的原因,一直没有空出足够时间来进行学习.最近自从决定本科毕业出来找工作之后,渐渐开始接触大数据行业的技术,现在觉得是时候把R拿下 ...
- 掌握JavaScript中的Promise,实现异步编程
事件循环 基本介绍 JavaScript是一门单线程的编程语言,所以没有真正意义上的并行特性. 为了协调事件处理.页面交互.脚本调用.UI渲染.网络请求等行为对主线程造成的影响,事件循环(event ...
- 彻底理解Javascript 中的 Promise(-------------------------------***---------------------------------)
ES6原生提供了 Promise 对象. 到底是何方妖怪呢?打出来看看: 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个 ...
随机推荐
- 【UE4 设计模式】设计模式一些概念
定义 设计模式是一套被反复使用的.多数人知晓的.经过分类编目的.代码设计经验的总结. 使用设计模式是为了重用代码.让代码更容易被他人理解.保证代码可靠性. 四人帮 GOF ( Gang of Four ...
- UltraSoft - Alpha - Scrum Meeting 2
Date: Apr 09th, 2020. 会议内容为完成初步的任务分工. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM.后端 继续Django tuto ...
- Noip模拟37 2021.8.12
T1 数列 真是考场上不是数学的乱推柿子,想定理,是数学的没想出来.. 比较悲伤... 列柿子不用动脑子,就是没有想出来$EXgcd$解不定方程,淦.. 解处一组解后利用比较显然的性质: $x+\fr ...
- Noip模拟18 2021.7.17 (文化课专场)
T1 导弹袭击(数学) 显然,我们要找到最优的A,B使得一组a,b优于其他组那么可以列出: $\frac{A}{a_i}+\frac{B}{b_i}<\frac{A}{a_j}+\frac{B} ...
- 「总结」$dp1$
大概就是做点题. 先列一下要做的题目列表,从\(UOJ\)上找的. 129寿司晚宴 348州区划分 370滑稽树上滑稽果 457数树 22外星人 37主旋律 300吉夫特 196线段树 311积劳成疾 ...
- iptables 原理及应用
转自:iptables 原理及应用 iptables是一个Linux下优秀的nat+防火墙工具,我使用该工具以较低配置的传统pc配置了一个灵活强劲的防火墙+nat系统,小有心得,看了网上也有很多这方面 ...
- hdu 2189 来生一起走(DP)
题意: 有N个志愿者.指挥部需要将他们分成若干组,但要求每个组的人数必须为素数.问不同的方案总共有多少.(N个志愿者无差别,即每个组的惟一标识是:人数) 思路: 假设N个人可分为K组,将这K组的人数从 ...
- 在Delphi中高效执行JS代码
因为一些原因,需要进行encodeURIComponent和decodeURIComponent编码,在Delphi中找了一个,首先是发现不能正确编码+号,后面强制处理替换了,勉强可用. 后面发现多次 ...
- ansible安装和批量执行命令
yum install -y ansible 编辑 /etc/ansible/hosts 文件 # This is the default ansible 'hosts' file.## It sho ...
- Matlab 中 arburg 函数的理解与实际使用方法
1. 理解 1.1 Matlab 帮助: a = arburg(x,p)返回与输入数组x的p阶模型相对应的归一化自回归(AR)参数. 如果x是一个向量,则输出数组a是一个行向量. 如果x是矩阵,则参数 ...