Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。解决来之前在请求中回调请求产生的回调地狱,使得现在的代码更加合理更加优雅,也更加容易定位查找问题。
Promise有三种状态
- Pending(进行中,初始状态,既不是成功,也不是失败状态)
- Resolved(又称 Fulfilled,意味着操作成功完成)
- Rejected(意味着操作失败)
/** 基于promise的ajax get请求
* @param url <string> 请求的路径
* @param query <object> 请求要携带的参数
* @param [isJson] <boolean> 请求返回的数据是否是json格式,默认为true
*
*/
fetch (url, query, isJson = true) {
if (query) {
url += '?'
// 遍历query,把每一个属性都拼接再url后面
for (var key in query) {
url += `${key}=${query[key]}&`
}
// 拼接完成以后多出一个&
url = url.slice(0, -1) // 从0开始截取到倒数第一个结束,只保留了除最后一个&以外的字符串
}
// 在这里需要把promise return出去,这样将来调用这个方法才能.then
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.send()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(isJson ? JSON.parse(xhr.responseText) : xhr.responseText)
} else {
reject()
}
}
}
})
}
}
Promise.all
这个方法返回一个新的promise对象,该promise对象在数组里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。
1 2 3 4 5 6 7 8 9 10 | var promise1 = Promise.resolve(3); var promise2 = 42; var promise3 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]).then(function(values) { // values就是这三个promise resolve的时候传递过来的参数构成的数组 console.log(values); }); |
Promise.race
Promise.race() 类似于Promise.all() ,区别在于它有任意一个完成就算完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | let p1 = new Promise(resolve => { setTimeout(() => { resolve('I\`m p1 ') }, 1000) }) let p2 = new Promise(resolve => { setTimeout(() => { resolve('I\`m p2 ') }, 2000) }) Promise.race([p1, p2]).then(value => { // 这里的value就是第一个resolve的参数 console.log(value) // I`m p1 }) |
Promise.resolve
1 2 3 4 5 | const pro = Promise.resolve(123); pro.then(function(value) { console.log(value) // 123 }) |
Promise.reject
1 2 3 4 5 6 7 | const pro = Promise.reject(new Error('abc')); pro.then(() => { // 不会走这里 }).catch(err => { console.log(err) // Error: abc }) |
添加一点小知识
-
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
-
micro-task(微任务):Promise,process.nextTick
进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务