理解ES6中的Promise
一、Promise的作用
在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理。
这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这个新的ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就需要在回调函数中再写一个异步请求,然后在这个异步函数的回调函数里在写相应的数据处理。要是连续嵌套个三四层,往往就很恶心了。
写起来就像下面这样:
$.ajax({
type:'get',
url:'url_1',
data: 'data'
success : function(res){
//相应的数据处理
var data = res.data
$.ajax({
type:'get',
url:'url_2',
data: data
success : function(res){
//相应的数据处理
$.ajax({
type:'get',
url:'url_3',
data: data
success : function(res){
//相应的数据处理
}
})
}
})
}
})
在这种情况下Promise就能发挥它的威力了;
二、来一个实例
先不谈语法,下面先来一个实例,建立感性的认识
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
</head>
<body>
</body>
<script>
function a(data){
return new Promise(function(resolve,reject){
console.log("我是从上一个回调函数里传过来的数据",data) ;
$.ajax({
type:'post',
dataType: 'jsonp',
url:'http://api.money.126.net/data/feed/0000001,1399001', //jsonp跨域调用上证与深证的股票指数
data:{
},
success : function(res){
console.log(res) ;
resolve(res) ;
},
error:function(res){
console.log("Error:") ;
console.log(res) ;
reject(res) ;
}
})
});
}
function b(data){
return new Promise(function(resolve,reject){
console.log("我是从上一个回调函数里传过来的数据",data) ;
$.ajax({
type:'post',
dataType: 'jsonp',
url:'https://api.douban.com/v2/movie/top250', //跨域调用豆top250的电影
success : function(res){
console.log(res) ;
resolve(res) ;
},
error:function(res){
console.log("Error:") ;
console.log(res) ;
reject(res)
}
})
});
}
a().then(b).then(a).then(b).catch(function(a){console.log("final Error:",a)}) ;
</script>
</html>
打印结果如下所示:
可以发现,
Promise
通过简单的链式调用就能得到之前多层回调才能达成的效果;而且从代码的结构来看,有效地减小了各个请求之间的耦合;
三、深入Promise
别的不谈,先打印一下 Promise
, console.dir(Promise)
, 看看它究竟是哪号人物:
原来
Promise
本身是一个构造函数,自己身上有all
、reject
、resolve
这几个的方法,在其prototype
上有then
、catch
这两个方法。那么用Promise new出来的对象也会有then
、catch
这两个方法。
四、注意上面实例中的resolve与reject
1、我们发现,在 new Promise(function(resolve,reject){})
里传了两个方法 resolve
、 reject
作为参数,这两个方法通常会在函数的回调里被用到。一旦执行到resolve()
或者 reject()
,那么这个函数会停止执行,然后触发后面的 then()
或者 catch()
方法。准确一点来说,执行到resolve()
会触发 then()
方法,执行到 reject()
会触发 catch()
方法。
2、resolve
和 reject
方法里可以传入参数 ,就像 resolve(data)
和 reject(data)
。 如果这样做 ,那么在后面的 then()
或者 catch()
里传入一个带参数的函数 , 就像 then(function(data){})
或者 catch(function(data){})
, 就能得到 data
的数据 。
3、说的再专业一些,Promise
对象有三种状态,他们分别是:
- pending: 等待中,或者进行中,表示还没有得到结果
- resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
- rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行
这三种状态不受外界影响,而且状态只能从 pending
改变为 resolved
或者rejected
,并且不可逆。在 Promise
对象的构造函数中,resolve
和 reject
就是用来处理Promise的状态变化。
一般来说,调用 resolve
或 reject
以后,Promise 的使命就完成了,后继操作应该放到 then
或者 catch
方法里面,而不应该直接写在 resolve()
或 reject()
的后面 (事实的情况是,resolve()
或 reject()
的后面的代码也不会执行)。
五、new Promise()
里的函数是立刻执行的
需要注意的的是,new Promise()
里的函数是立刻执行的 ,也就是说 ,当你执行下面这段代码时,就已经开始执行异步请求了:
<script>
new Promise(function(resolve,reject){
$.ajax({
type:'post',
dataType: 'jsonp',
url:'http://api.money.126.net/data/feed/0000001,1399001',
data:{
},
success : function(res){
console.log(res) ;
resolve(res) ;
},
error:function(res){
reject(res) ;
}
})
});
</script>
这也是为什么,在上面第二段的实例中,需要用 a()
和 b()
函数把 new Promise()
给包起来
六、then()
函数的返回值一定是 Promise
对象
还需要注意的的是,then()
函数的返回值一定是 Promise
对象,哪怕手动 return
一个值也无济于事,如下面的代码,照样能运行成功:
a().then(function (){console.log("hello");return 1}).then(b) ;
这也解释了为什么我们可以链式调用 then()
函数。
七、Promise.all()
与Promise.race()
的用法
想要从两个不同的 ajax
请求里分别获得信息,这两个任务是可以并行执行的,就可以用 Promise.all()
实现:
<script>
var p1 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
} ;
var p2 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 1000, 'P2');
});
} ;
// 同时执行p1和p2,并在它们都完成后执行then
var start = function(){
Promise.all([p1(), p2()]).then(function (results) {
console.log(results); // 获得一个Array: ['P1', 'P2']
});
}
</script>
有些时候,多个异步任务是为了容错。比如,分别发两个不同的 ajax
请求读取用户的个人信息,只需要获得先返回的结果即可,这种情况下,就可以用Promise.race()
实现:
<script>
var p1 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
} ;
var p2 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 1000, 'P2');
});
} ;
var start = function(){
Promise.all([p1(), p2()]).then(function (results) {
console.log(results); // 'P1'
});
}
</script>
由于 p1
执行较快,Promise
的 then()
将获得结果 'P1'
。 p2
仍在继续执行,但执行结果将被丢弃。
如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。
参考文献:
阮一峰ES6入门
廖雪峰的官方网站
sitepoint
"吕大豹"的博客园
原文地址:
王玉略的个人网站
理解ES6中的Promise的更多相关文章
- 深入理解es6中的Promise
https://www.jianshu.com/p/9e4af5b77253 https://zhuanlan.zhihu.com/p/30797777 https://segmentfault.co ...
- 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理
理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...
- 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...
- es6中的Promise学习
关于Promise Promise实例一旦被创建就会被执行 Promise过程分为两个分支:pending=>resolved和pending=>rejected Promise状态改变后 ...
- ES6中的Promise和Generator详解
目录 简介 Promise 什么是Promise Promise的特点 Promise的优点 Promise的缺点 Promise的用法 Promise的执行顺序 Promise.prototype. ...
- es6中的promise对象
Promise是异步里面的一种解决方案,解决了回调嵌套的问题,es6将其进行了语言标准,同意了用法,提供了`promise`对象, promise对象有三种状态:pending(进行中) .Resol ...
- ES6中的Promise用法
Node的产生,大大推动了Javascript这门语言在服务端的发展,使得前端人员可以以很低的门槛转向后端开发. 当然,这并不代表迸发成了全栈.全栈的技能很集中,绝不仅仅是前端会写一些HTML和一些交 ...
- ES6中的Promise使用方法与总结
在javascript中,代码是单线程执行的,对于一些比较耗时的IO操作,都是通过异步回调函数来实现的. 但是这样会存在一个问题,当下一个的操作需要上一个操作的结果时,我们只能把代码嵌到上一个操作的回 ...
- 彻底理解Javascript 中的 Promise(-------------------------------***---------------------------------)
ES6原生提供了 Promise 对象. 到底是何方妖怪呢?打出来看看: 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个 ...
随机推荐
- python中stack在实际中的简单应用之平衡符号
很多书籍都在讲stack的概念和使用方法,等我们把概念熟悉后,发现不知道在什么场景下使用 该结构体,这里就列几个实用的例子,让大家了解一下stack在实际中的用处和厉害之处. 由于stack中的特点是 ...
- 自学vue笔记 (二) : 实例与生命周期
一: 什么是实例 我们说了,Vue 应用都应该从构建一个 Vue 实例开始.它管理着挂载在它身上的所有内容,因此实例是一个根实例, 所有的组件都应该挂载在根实例上面.创建一个 Vue 实例,需要通过 ...
- Spark基础脚本入门实践1
1.创建数据框架 Creating DataFrames val df = spark.read.json("file:///usr/local/spark/examples/src/mai ...
- 如何把checkbox做成radio一样的单选效果
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>复 ...
- 在线画UML图的工具
工作需要在线画各种UML图,类图.协作图.用例图等等,调查了一些在线画UML图的工具,有的做的很好但要收费,例如:http://www.gliffy.com/,发现现在免费好用的是ProcessOn: ...
- 常用的.NET开源项目(转)
Json.NET http://json.codeplex.com/ Json.Net是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Lin ...
- Java后端学习路线图,你真的只需要这一张!
前言 学习路线图往往是学习一样技术的入门指南.网上搜到的Java学习路线图也是一抓一大把. 今天我只选一张图,仅此一图,足以包罗Java后端技术的知识点.所谓不求最好,但求最全,学习Java ...
- 安装和配置jBPM4,并举个hello.w
至于网上很复杂,但又不懂的插件,我们先不鸟他. myeclipse8\dropins这里就是给我们放插件的,类似SVN之类的.所以小生也修改了下,共享了下.只有放在目录下,打开应该可以的.下面是链接. ...
- Jenkins 批量删除历史构建
在一次巡查 Jenkins 时,发现很多个项目的历史构建比较多,这些历史构建对于现在来说又没有什么用处,那么想把它删除,但是一个一个删除很累,毕竟总共加起来有上千个,历史构建,而且还不只是一个项目.那 ...
- [Luogu 3613] 睡觉困难综合征
Description 给定一棵 \(n\) 个点的树,每个点上有位运算 \(opt\) 和一个权值 \(x\),位运算有 &,|,^ 三种. 要求支持: 修改点 \(v\) 的 \(opt\ ...