Promise 阅读笔记
为什么会有 promise?
根据官方的说法,promise 的出现是为了解决 callback hell 回调地狱,将横向的嵌套回调改为可以纵向以 then 的方式加载执行。
简介 & 用法
// 通过new Promise 得到一个promise的实例,也就是一个普通对象。 // 构造函数需要传一个 callback 去定义何时执行 resolve,reject 这两个函数 var promise = new Promise(function(resolve, reject) { if('code') { // code 可能是异步操作成功判断条件 resolve() } else { reject() } }) // then的两个参数(resolve, reject) promise.then(function(){ console.log('success') },function(){ console.log('failure') })
三种状态
[[PromiseValue]] //内部属性 -- 状态
//而且这个状态不可随意更改,只跟resolve ,reject函数执行有关
实例内部有三种状态标示
- Pending 进行中 即构造函数执行开始
- Resolved 已成功 resolve函数 执行
- Rejected 已失败 reject函数 执行
而且只能由Pending --> Resolved,Pending-->Rejected ,即成功或失败
这个状态变化的条件是由我们控制的。一个请求返回成功状态码... 等等
方法
Promise.prototype.then()
两个参数 resolve, reject
function getPromise (status) { return new Promise(function(resolve, reject) { let time = Date.now() console.log('time') setTimeout(()=>{ if(status) { resolve(time) } else { reject(new Error('status error')) } },1000) }) } getPromise(1).then((time)=>{ console.log('1',Date.now()-time) return Date.now()-time },(err)=>{ console.log(err,'err') return err }).then((time)=>{ console.log('2',time) return time },(err)=>{ console.log(err,'err') return err }).then((time)=>{ console.log('3',time) },(err)=>{ console.log(err,'err') }) // "time" "1" 1002 "2" 1002 "3" 1002 // // status传0 getPromise(0).then((time)=>{ console.log('1',Date.now()-time) return Date.now()-time }, (err)=>{ console.log(err,'err') return err }).then((time)=>{ console.log('2',time) return time },(err)=>{ console.log(err) return err }).then((time)=>{ console.log('3',time) },(err)=>{ console.log(err) }) // "time" [object Error] { ... } "err" "2" [object Error] { ... } "3" [object Error] { ... } // 很有意思的是第一次promise 异步代码失败 执行reject, 但是后面的都是执行resolve,而且resolve的参数都已经是error对象了
- 这里我们定义了一个函数来返回一个promise实例,然后实例可以执行then。只要构造函数执行,里面的代码就会执行,异步代码也会放到异步队列,当异步代码执行完(这里就是我们的setTimeout),根据我们提供的条件,成功执行resolve,失败就reject。当然条件都是我们自己规定的,比如异步请求的code...
- 只要异步代码成功,我们的条件成功,就可以无限then。因为then传的resolve,reject 执行完都后,都会返回一个promise实例。另外,如果我们在resolve里return一个新的promise实例,那么这个promise实例将作为新的then的调用者。如果return一个非promise实例,都会作为参数传递给下面的resolve..
- 无论是成功的结果还是error信息,都会被一级级传递下来。利用此,举个栗子我们有三个请求,每个请求的参数都依赖于上一个请求的结果,用promise就很简洁... 另外收集错误也是可以做到的。
举个栗子
var getJson = function (url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest () xhr.open('get',url) xhr.onreadystatechange = callback xhr.responseType = 'json' xhr.send(null) function callback () { if(this.readyState !== 4) return if(this.status === 200) { resolve(this.response) }else{ reject(new Error(this.statusText)) } } }) } getJson('api/list').then((response)=>{ console.log(response) return getJson(response.url) },(err)=>{ console.log(err) return err }).then((response)=>{ console.log(response) },(err)=>{ console.log(err) }) //这个就是典型的第二个请求的参数依赖于第一个请求返回的结果。 业务中还有那种比如两三个请求都成功了,我们才处理,渲染的。用promise都比较好处理
Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
getPromise(0).then((time)=>{ console.log('1',Date.now()-time) return Date.now()-time },(err)=>{ console.log(err,'err') return err }).then(null,(err)=>{ console.log(err,'err') return err }).then(null,(err)=>{ console.log(err,'err') })
类似于我们上面的例子把后面两个 then 的 resolve 去掉 改为 null,也就是说,当我们需要在第二个 then 里面有目的的收集错误的时候,我们可以直接用catch方法,省去then写法的麻烦。类似于这样
getPromise(0).then((time)=>{ console.log('1',Date.now()-time) return Date.now()-time },(err)=>{ console.log(err,'err') return err }).catch((err)=>{ console.log(err,'err') return err }).catch((err)=>{ console.log(err,'err') })
当然我们不会写两个 catch。这里只是改写一下 then。更多详细的直接看 es6 入门里面,讲的很详细,因为 catch 我用的也不是很多。
Promise.all()
all 的主要用途就是多个请求,同时成功了,再做某事,参数是一个数组,数组里面是 Promise 实例
注意这个方法是构造函数上的方法,用于将多个 Promise 实例,包装成一个新的 Promise 实例
两个Promise,请求 1.getExams 2.getQuestion Promise.all([getExams(examId), getQuestion(questionId)]).then((exams,questions)=>{ console.log(exams,questions) })
应用场景就是我们多个请求都成功,才能做什么。
Promise.race()
跟 all 用法类似,都是传多个promise对象。根据 race 的意思,我们大概知道是干嘛的了。哪个先完成,就返回哪个的数据。应用场景大概是两个服务器,比较哪个快。但是现在服务器 都会通过nginx 做负载均衡,也不需要前端去关注这些东西。
Promise.race([getExams(examId), getQuestion(questionId)]).then((data)=>{ console.log(data) })
race 还要一个应用场景就是可以做超时处理。
const timeOut = 3000; const delay = function delay(time) { return new Promise((resolve) => { setTimeout(() => { resolve(JSON.stringify({ code: 0, msg: '请求超时', })); }, time); }); }; const response = Promise.race([delay(timeOut), fetch('api/list')]);
当 fetch 超过 3 秒,delay 的 promise 对象 resolve(),结果就会赋值给 response,此时的 response 读取到的已经是超时的。但是还是无法 abort 请求,这算是 promise 的一个痛点,本次笔记记录先到此,其实 API 书中都比较清楚了。关键还是项目中的应用。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 观察者(发布订阅)模式
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不错,我写过源代码分析:
http://www.cnblogs.com/pzhu1/p/8365963.html
总结的很不错,感谢博主的分享。。