blog
blog copied to clipboard
promise阅读笔记
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我用的也不是很多 es6入门阮一峰-promise
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 书中都比较清楚了。关键还是项目中的应用。
推荐链接
阮一峰的文章比较详细,博主挑一些主要的做了总结,再看一遍增加记忆了,感谢
总结的很不错,感谢博主的分享。。
不错,我写过源代码分析: http://www.cnblogs.com/pzhu1/p/8365963.html