Promise

回调地狱,服务器请求数据,掉回调函数,然后在回调函数里面发请求,回调函数里面套回调函数,形成回调地狱。

错误是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实例状态变为失败,同时可以指定失败的原因。

基本编码流程:

  1. 创建Promise实例对象(pending状态),传入executor函数

  2. 在executor中启动异步任务

  3. 根据异步任务的结果,做不同的处理

    3.1 如果异步任务成功,调用resolve(value),让Promise实例状态变为成功,同时指定value

    3.2 如果异步任务失败了,调用reject(reason),让Promise实例状态变为失败,同时指定失败的reason

    setTimeout是浏览器的一个方法不是回调函数,里面的函数是回调函数。状态只能切换一次pending=>fulfilled/pending=>rejected。

  4. .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

  1. Promise构造函数: new Promise((resolve,reject)=>{异步任务resolve();reject()})

  2. Promise.prototype.then: Promise实例.then(成功的回调:(response)=>{},失败的回调:(reson)=>{})

    .then方法的返回值是一个全新的Promise实例对象。如果Promise返回值是非Promise值,新Promise实例成功,获得的值是Promise实例的返回值。如果返回值是Promise实例,返回成功的Promise新实例就成功,返回失败的Promise实例,新实例就失败,获得的值就是返回的实例发出的值。如果抛出异常,新实例的状态是rejected,reason为抛出的那个异常。

  3. Promise.prototype.catch:Promise实例.catch(失败的回调:(reson)=>{})相当于Promise实例.then(undefined,(reason)=>{}),回调函数是一组的,如果不写成功的回调函数没关系,如果不写失败回调遇到之后的会抛出异常

  4. Promise.resolve方法返回一个状态为fulfilled或rejected的Promise实例对象

    value的值可能是非Promise也有可能是Promise值

  5. Promise.reject方法返回一个状态为rejected的Promise实例对象

  6. Promise.all方法

    Promise.all(promiseArr)

    promiseArr包含n个Promise实例的数组

    返回一个新的Promise实例,只有所有的promise都成功才成功,有一个失败就失败。成功的response是所有成功的数组,失败的reason是第一个失败的reason。

  1. 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')
}
)

微队列里需要知道的是Promise的回调函数

posted on 2022-12-06 17:59  fangpiandang  阅读(108)  评论(0编辑  收藏  举报