JavaScript中Promise 使用详解
Posted 萌萌的DDD
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript中Promise 使用详解相关的知识,希望对你有一定的参考价值。
Part 01 - Promise 概述
Promise 一种更优的异步编程统一方案
传统的异步编程如ajax:是通过回调函数来进行请求后的一系列执行。
但是如果直接使用传统的回调的方式去完成复杂的异步流程,就无法避免大量的回调函数的嵌套。
这样就容易发生回调地狱,导致代码卡顿
回调地狱
get('url',function(){
get2('url2',function(){
get3('url3',function(){
})
})
})
最终为了解决回调地狱问题,CommonJS社区提出了Promise方案,最终在ES5被定为标准规范。
Promise是什么?
Promise实际上就是一个对象,用来表述一个异步任务最终结果是成功还是失败。
Part 02 - Promise 基础用法
const promise = new Promise(function(resolve, reject) {
// 回调函数内部 用于表示承诺的执行、
// 承诺执行成功
resolve('resolve200')
// 承诺执行失败 新建一个失败对象
reject(new Error('reject500'))
})
promise.then(function(value) {
// 参数1 resolve函数, 用于执行成功的结果
console.log(value, 'then');
}, function(err) {
// 参数2 reject函数, 用于执行失败的结果
console.log(err, 'error');
})
Part03 - Promise 使用案例
使用promise封装ajax请求的案例
const ajax = function(url) {
// 封装一个 ajax函数 并将promise作为函数返回值
return new Promise(function(resolve, reject) {
// 创建http对象
var xhr = XMLHttpRequest()
// 准备发送请求类型和地址
xhr.open('GET', url)
// h5新语法 将接收到的数组固定为json格式
xhr.responseType = 'json'
xhr.onload = function(res) {
if (this.status === 200) {
resolve(res)
} else {
reject(new Error(this.statusText))
}
}
xhr.send()
})
}
ajax('url地址').then(function(value) {
console.log(value);
}, function(err) {
console.log(err);
})
Part04 - Promise 的链式调用
Promise的本质也就是使用回调函数,定义异步任务过后所需要执行的任务
而Promise将回调函数分为了两种形式
- onFulfilled 成功之后的回调
- onRejected 失败之后的回调
-
ajax(url) .then(function onFulfilled(res) { console.log(res); }, function onRejected(err) { console.log(err); })
每一个then方法都会返回一个全新的Promise对象,目的是形成一个以Promise对象为结尾的新的链条。
ajax('url地址').then(function(value) {
console.log(value);
}) // => Promise
.then(function(value) {
console.log(111);
}) // => Promise
.then(function(value) {
console.log(222);
}) // => Promise
.then(function(value) {
console.log(333);
}) // => Promise
.then(function(value) {
console.log(444);
}) // => Promise
.then(function(value) {
console.log(555);
}) // => Promise
.then(function(value) {
console.log(666);
})
每次链式调用后的then,实际上都是为了上一个then返回的Promise进行回调后的执行
因此这里的返回则为同步类型 依次执行
ajax('url地址').then(function(value) {
console.log(value);
return ajax('url地址').then(function(value) {
console.log(111);
})
})
前面then方法中回调函数的返回值会作为后面then方法回调的参数
如果回调中返回的是Promise。那么后面的then方法的回调会等待他的结束
通过链式调用可以避免多次嵌套回调,保证异步请求的扁平化。
Part05 - Promise 的异常处理
当Promise没有正常请求后,则会执行onRejected函数
或者当resolve函数中出现了异常,或者我们手动抛出了一个一场,那么onRejected函数也会执行
我们可以通过Promise实例的catch方法去注册onRejected回调
ajax('url地址').then(function(value) {
console.log(value);
}).catch(function(err) {
console.log(err);
})
unhandledrejection事件
可以抛出在浏览器中没有捕获到的异常
window.addEventListener('unhandledrejection', event => {
const { reason, promise } = event
console.log(reason, promise);
// reason=> Promsie 失败的原因,一般是一个错误对象
// promise => 出现异常的Promise 对象
event.preventDefault()
}, false)
Part06 - Promise 的并行执行
当遇到多个可以同时执行的异步任务时,就需要使用 Promise.all
。
Promise.all()
参数:数组
数组内部是每一个请求
返回值:数组形式的promise对象
var promise = Promise.all([
ajax(url1),
ajax(url2)
])
promise.then(function(res) {
console.log(res);
})
const p1 = async () => {}
const p2 = async () => {}
const p3 = async () => {}
const [result1, result2, result3] = await Promise.all([p1, p2, p3])
console.log(result1)
console.log(result2)
console.log(result3)
ajax('/api/users.json')
ajax('/api/posts.json')
ajax('/api/urls.json')
.then(value => {
const urls = Object.values(value)
const tasks = urls.map(url => ajax(url))
return Promise.all(tasks)
})
.then(values => {
console.log(values)
})
只有所有的请求都结束了,才会返回一个Promise对象
如果其中一个请求失败了,则会返回一个失败的对象。
Promise.all()等待所有任务结束
Promise.race()当第一个任务完成则返回promise
Part07 - Promise 的执行顺序
即使promise没有任何的异步调用,仍然会被挂起进行异步等待
回调队列中的任务被称之为【宏任务】
宏任务执行的过程中可能临时加上一些额外需求,对于这些额外的需求可以选择作为一个新的宏任务进到队列中排队。
也可以作为当前任务的【微任务】,直接在当前任务结束过后立即执行。
promise的回调则会作为微任务执行。会在本轮调用的末尾进行执行
以上是关于JavaScript中Promise 使用详解的主要内容,如果未能解决你的问题,请参考以下文章
AngularJS 中的Promise --- $q服务详解
4.2 前端开发日报——JS异步编程之Promise详解和使用总结