回调地狱,服务器请求数据,掉回调函数,然后在回调函数里面发请求,回调函数里面套回调函数,形成回调地狱。
错误是js引擎抛出的,也可以自己抛出,throw new Error('错误信息'),抛什么都可以,一般是抛错误对象,错误对象包括message和stack。捕获错误方法:try{代码}catch(错误信息){xxx}。
Promise是JS中做异步编程的新方案,旧方案是用纯回调的方法。Promise是一个浏览器内置的构造函数,Promise的实例对象可以封装一个异步操作,并可以获取其失败/成功的值。
创建实例的时候一定要传一个函数,它是回调函数,是同步的,它叫executor函数。每一个Promise实例对象都有三种状态,分别为pending,fulfilled,rejected。每个Promise实例创建出来的时候,默认是pending状态。executor函数会接收到两个参数,它们都是函数,分别用形参:resolve、reject接收。调用resolve会让Promise实例状态变为成功,同时可以指定成功的value。调用reject会让Promise实例状态变为失败,同时可以指定失败的原因。
基本编码流程:
-
创建Promise实例对象(pending状态),传入executor函数
-
在executor中启动异步任务
-
根据异步任务的结果,做不同的处理
3.1 如果异步任务成功,调用resolve(value),让Promise实例状态变为成功,同时指定value
3.2 如果异步任务失败了,调用reject(reason),让Promise实例状态变为失败,同时指定失败的reason
setTimeout是浏览器的一个方法不是回调函数,里面的函数是回调函数。状态只能切换一次pending=>fulfilled/pending=>rejected。
-
.then方法是Promise构造函数原型链上的方法,是给Promise实例用的方法。用来指定成功和失败的回调。等到成功或是失败之后调用。是异步的回调。一个Promise实例指定了多个成功/失败的回调函数,都会调用的。
404是能访问到服务器,但是没有这个资源
在promise执行器函数中发送ajax请求:
const p = new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=>{//异步的
if(xhr.readyState == 4) {//readyState=4是代表获得了响应
if(xhr.status === 200) {//请求成功
resolve(xhr.response)
}else{//请求出现问题
reject('请求出错')
}
}
}
xhr.responseType = 'json'
xhr.open('GET', 'https://dog.ceo/api/breeds/image/random/3')
xhr.send()
})
p.then(
(value)=>{
console.log('test',value)
},
(result)=>{
console.log(result)
}
)
用函数+Promise封装AJAX请求,把上面的地址参数写活:
function sendAjax(url, data) {
return new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {//这段是异步的
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response)
}else{
reject('请求出错')
}
}
}
// 把参数变成字符串拼接
let str = ''
for (let key in data) {
str += `${key}=${data[key]}&`
}
str = str.slice(0,-1)
xhr.responseType = 'json'
xhr.open('GET',url+'?'+str)
xhr.send()
})
}
sendAjax('https://dog.ceo/api/breeds/image/random/3').then(
(value)=>{
console.log(value)
},
(result)=>{
console.log(result)
}
)
用纯回调封装AJAX请求
function sendAjax(url,success,error){
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300)success(xhr.response)
else error('失败了')
}
}
xhr.responseType = 'json'
xhr.open('GET',url)
xhr.send()
}
sendAjax('https://dog.ceo/api/breeds/image/random/3',
(result)=>{console.log(result)},
(reason)=>{console.log(reason)}
)
Promise构造函数的API
-
Promise构造函数: new Promise((resolve,reject)=>{异步任务resolve();reject()})
-
Promise.prototype.then: Promise实例.then(成功的回调:(response)=>{},失败的回调:(reson)=>{})
.then方法的返回值是一个全新的Promise实例对象。如果Promise返回值是非Promise值,新Promise实例成功,获得的值是Promise实例的返回值。如果返回值是Promise实例,返回成功的Promise新实例就成功,返回失败的Promise实例,新实例就失败,获得的值就是返回的实例发出的值。如果抛出异常,新实例的状态是rejected,reason为抛出的那个异常。
-
Promise.prototype.catch:Promise实例.catch(失败的回调:(reson)=>{})相当于Promise实例.then(undefined,(reason)=>{}),回调函数是一组的,如果不写成功的回调函数没关系,如果不写失败回调遇到之后的会抛出异常
-
Promise.resolve方法返回一个状态为fulfilled或rejected的Promise实例对象
value的值可能是非Promise也有可能是Promise值
-
Promise.reject方法返回一个状态为rejected的Promise实例对象
-
Promise.all方法
Promise.all(promiseArr)
promiseArr包含n个Promise实例的数组
返回一个新的Promise实例,只有所有的promise都成功才成功,有一个失败就失败。成功的response是所有成功的数组,失败的reason是第一个失败的reason。
-
Promise.race方法,Promise.race(promiseArr)
promiseArr:包含n个Promise实例的数组
返回一个新的Promise实例,成功失败取决于第一个返回结果的promise。
执行器函数抛出异常,如果当前pending就会转变为rejected,状态只改一次,抛完异常之后,代码就不会走了,throw
可以先指定回调再改变状态常见,也可以延迟一会再指定回调,得指定完回调并且状态改变了,才能拿到数据,拿数据就是回调函数里面的操作,先改状态就存一下状态,先指定回调就存一组回调。
使用then的链式调用解决回调地狱:
function sendAjax(url, data) {
return new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300){
resolve(xhr.response)
}else{
reject('请求出错')
}
}
}
// 把参数变成字符串拼接
let str = ''
for (let key in data) {
str += `${key}=${data[key]}&`
}
str = str.slice(0,-1)
xhr.responseType = 'json'
xhr.open('GET',url+'?'+str)
xhr.send()
})
}
let then = sendAjax('https://dog.ceo/api/breeds/image/random/3')
.then(
(value)=>{
console.log('第1次请求成功',value)
return sendAjax('https://dog.ceo/api/breeds/image/random/3')
},
(reason)=>{
console.log(reason)
}
)
.then(
value =>{
console.log('第2次请求成功',value)
return sendAjax('https://dog.ceo/api/breeds/image/random/3')
},
reason =>{
console.log('第2次请求失败',reason)
}
)
.then(
value => {console.log('第三次请求成功',value)},
reason => {console.log('第三次请求失败',reason)}
)
让Promise链停下来的方法,就是在失败的回调函数中,返回一个pending的Promise实例,return new Promise(()=>{})
当使用promise的then链式调用,在最后用catch指定一个失败的回调,回调拿到的原因就是失败那次的原因,前面任何操作出错,都会传到最后失败的回调中。原理,底层在每个失败的回调函数中抛出了错误原因throw reason,然后在最后捕获了失败。
Promise优势,指定回调比较灵活,解决回调地狱
await 只能用在async函数中,可以获得Promise实例成功之后的响应。用try catch,包裹它,可以捕获请求失败的异常。按顺序等结果。!(async()=>{const result = await p})()
函数被async修饰,返回值是一个Promise实例,Promise实例的结果由函数的返回值决定,如果await等的是非promise实例直接返回那个值,如果await等的是实例对象,await获得的是promise对象成功的值。async函数里可以没有await。如果await的实例对象失败了,需要用trycatch捕获异常。
await后面的代码,会放到成功的回调里面:
async function demo() {
const result = await p
console.log('xxxx')
}
=
p.then(
result=>{
console.log(result)
console.log('xxxxx')
}
)