Open sunyongjian opened 7 years ago
为什么会有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 ,即成功或失败
这个状态变化的条件是由我们控制的。一个请求返回成功状态码... 等等
两个参数 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方法是.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我用的也不是很多 es6入门阮一峰-promise
all 的主要用途就是多个请求,同时成功了,再做某事 参数是一个数组,数组里面是Promise实例
注意这个方法是构造函数上的方法,用于将多个Promise实例,包装成一个新的Promise实例
两个Promise,请求 1.getExams 2.getQuestion Promise.all([getExams(examId), getQuestion(questionId)]).then((exams,questions)=>{ console.log(exams,questions) })
应用场景就是我们多个请求都成功,才能做什么。
跟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 书中都比较清楚了。关键还是项目中的应用。
推荐链接
es6入门阮一峰-promise javascript标准参考教材 剖析Promise内部结构
阮一峰的文章比较详细,博主挑一些主要的做了总结,再看一遍增加记忆了,感谢
总结的很不错,感谢博主的分享。。
不错,我写过源代码分析: http://www.cnblogs.com/pzhu1/p/8365963.html
promise
根据官方的说法,promise的出现是为了解决"callback hell"回调地狱, 将横向的嵌套回调改为可以纵向以then的方式加载执行。
实例内部有三种状态标示
Pending 进行中 即构造函数执行开始
Resolved 已成功 resolve函数 执行
Rejected 已失败 reject函数 执行
而且只能由Pending --> Resolved,Pending-->Rejected ,即成功或失败
这个状态变化的条件是由我们控制的。一个请求返回成功状态码... 等等
Promise.prototype.then()
两个参数 resolve, reject
这里我们定义了一个函数来返回一个promise实例,然后实例可以执行then。只要构造函数执行,里面的代码就会执行,异步代码也会放到异步队列,当异步代码执行完(这里就是我们的setTimeout),根据我们提供的条件,成功执行resolve,失败就reject。当然条件都是我们自己规定的,比如异步请求的code...
只要异步代码成功,我们的条件成功,就可以无限then。因为then传的resolve,reject 执行完都后,都会返回一个promise实例。另外,如果我们在resolve里return一个新的promise实例,那么这个promise实例将作为新的then的调用者。如果return一个非promise实例,都会作为参数传递给下面的resolve..
无论是成功的结果还是error信息,都会被一级级传递下来。利用此,举个栗子我们有三个请求,每个请求的参数都依赖于上一个请求的结果,用promise就很简洁... 另外收集错误也是可以做到的。
举个栗子
Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
类似于我们上面的例子把后面两个then 的 resolve去掉 改为null. 也就是说,当我们需要在第二个then 里面有目的的收集错误的时候, 我们可以直接用catch方法,省去then写法的麻烦。 类似于这样
当然我们不会写两个catch。这里只是改写一下then。 更多详细的直接看es6 入门里面,讲的很详细,因为catch我用的也不是很多 es6入门阮一峰-promise
Promise.all()
all 的主要用途就是多个请求,同时成功了,再做某事 参数是一个数组,数组里面是Promise实例
应用场景就是我们多个请求都成功,才能做什么。
Promise.race()
跟all用法类似,都是传多个promise对象。根据race 的意思,我们大概知道是干嘛的了。哪个先完成,就返回哪个的数据。 应用场景大概是两个服务器,比较哪个快。但是现在服务器 都会通过nginx 做负载均衡,也不需要前端去关注这些东西。
race还要一个应用场景就是可以做超时处理。
当fetch超过3秒,delay的promise对象resolve(), 结果就会赋值给response,此时的response读取到的已经是超时的。但是还是无法abort请求... 这算是promise的一个痛点
本次笔记记录先到此,其实API 书中都比较清楚了。关键还是项目中的应用。
es6入门阮一峰-promise javascript标准参考教材 剖析Promise内部结构