promise和jsonp

promise和jsonp

ajax回顾:

核心对象: xmlhttprequest

步骤

1.创建对象

2.打开请求地址(设置请求方式 GET 和 POST)

3.发送请求

4.监听请求

5.在请求监听中获取数据

回调地狱

回调的函数的无限嵌套 导致代码的可读性和可维护性差 以及代码的可扩展性差(代码失去了价值)

//需求 从a接口里面查询 用户名是李四的id
//从b接口查询对应的id的商品
//从c接口查询对应的商品的ip的商品类型
// 伪代码
AjaxUtil.get('a',{username:'李四'},(res)=>{ //a接口通过传姓名 获取返回的id
   AjaxUtil.get('b',{id:res.data.id},(res)=>{ //通过a接口返回的id 来获取对应的商品
       AjaxUtil.get('c',{id:res.data.id},(res)=>{ //通过b接口返回的商品id 来获取对应的商品类型
           console.log(res.data);
           ....
      })
  })
})
解决回调地狱

使用es6新增的promise对象

Promise对象

概述:

promise是es6新增的一个对象,他翻译为承诺,他有三种状态。promise设计为异步的

 

等待状态 (不能做其他的事情)

成功状态 (有成功调用的方法)

失败状态 (有失败调用的方法)

示例

// 使用new关键词 里面传递的参数是一个方法 这个方法里面通常存储一些异步的操作
// resolve表示成功执行的方法 reject失败执行的方法
var promise = new Promise((resolve,reject)=>{
   let timer = setTimeout(()=>{
       console.log('hello');
       //调用成功的方法 里面可以传参数
       // resolve('成功')
       reject('失败')
  },2000)
  })
then (resolve进入的方法)

//对应的promise对象有俩个方法 then 成功调用的方法 catch 失败调用的方法
//.then 在对应的resolve方法调用以后 .catch reject调用才能进入
promise.then((res)=>{
   //在then里面的方法 里面的参数为resolve的传递的参数
   console.log(res);
   console.log('我执行完了');
})
catch (reject进入的方法)

promise.catch((err)=>{
   //在catch里面的方法 里面的参数为reject的传递的参数
   console.log(err);
})
finally (只要达到成功或者是失败调用的方法)

//不管成功还是失败都会调用的方法(没有值传递)
promise.finally(()=>{
   console.log();
})

then catch finally 都是原型方法 Promise.prototype上面的方法

对象方法

Promise.reject() //返回的是一个promise对象(then获取的参数)

Promise.resolve() //返回的是一个promise对象(catch获取的参数)

Promise.all(promise数组) //返回也是一个promise数组 (并行执行 包含执行完成的)

Promise.race(promise数组) //返回的一个promise对象 (返回的是最先执行的promise)


//对象方法
Promise.reject('失败').catch((res)=>{
   console.log(res);
}) //失败
Promise.resolve('成功').then((res)=>{
   console.log(res);
}) //成功
var arr =  Promise.all([promise1,promise2,promise3]) //当所有的执行完才返回结果(数组)
var promise4 = Promise.race([promise1,promise2,promise3]) //race竞速 谁先执行完就是谁

利用promise来解决回调地狱

 

1.通过在对应的.then方法里面进入返回一个新的promise对象的形式


//解决回调地狱的方案
promise1.then((res)=>{
   console.log(res);
   return new Promise((resolve,reject)=>{
       setTimeout(()=>{
           console.log('jack');
           resolve('jack的promise')
      },1000)
  })
}).then((res)=>{
   console.log(res);
   return new Promise((resolve,reject)=>{
       setTimeout(()=>{
           console.log('吃饭了吗');
           resolve('吃饭了的promise')
      },1000)
  })
}).then((res)=>{
   console.log(res);
   setTimeout(()=>{
       console.log('你好');
  },1000)
})

ES7新增 async(异步) await(等待)

async修饰方法 await修饰对应的promise的

1.async修饰的方法会返回一个promise对象

2.await只能在async里面使用 (他是用来修饰promise对象的)

3.await会让当前的主线程等待 (上锁)当你执行完成(成功了或者失败了)才放行(解锁)

 


//使用es7的 async以及await来简化代码
window.onload = async ()=>{
   await new Promise((resolve,reject)=>{
       setTimeout(()=>{
           console.log('hello');
           resolve()
      },1100)
  })
   await new Promise((resolve,reject)=>{
       setTimeout(()=>{
           console.log('您好');
           resolve()
      })
  })
   console.log('执行完了');
}

使用promise封装对应的ajax


//xmlhttprequest有兼容 ie兼容 activeXObject
function initXhr(){
   if(XMLHttpRequest){
       return new XMLHttpRequest()
  }
   return new ActiveXObject("Micrisoft.XMLHTTP");//兼容ie6的
}
// 准备一个默认对象
var defaultObj = {
   method:'get', //请求方式 默认为get
   data:{}, //请求的数据 默认空对象
   url:"", //请求的url地址 默认为空字符
   dataType:"json", //请求过去的数据类型 默认为json
   async:true //是否异步 默认为异步
}
//传递一个对象
//请求方式 method 请求的数据data 请求的地址 url 对应的请求的数据data-type 是否异步 async
function ajax(option={}){
   //填值
   for(var key in defaultObj){
       //没有这个值进行填值 如果有这个就是返回本身
       option[key]?option[key]:option[key]=defaultObj[key]
  }
   //判断地址不为空
   if(option["url"]==""){
       throw new Error('地址不能为空')
  }
   //判断请求的方法不是get获取post 报错
   if(option["method"].toLowerCase()!='get' && option["method"].toLowerCase()!='post' ){
       throw new Error('请求方式错误')
  }
   //区别 设置请求的时候 get指定(?拼接) post指定(请求体中)
   let request =  initXhr()
   //指定请求
   //如果是get先做数据拼接
   if(option["method"].toLowerCase()=='get'){
       //取出对应的数据进行拼接
       for(let key in option["data"]){
           if(option["url"].indexOf('?')!=-1){
               option["url"] += `&${key}=${option["data"][key]}`
          }else{
               option["url"] += `?${key}=${option["data"][key]}`
          }
      }
       request.open('get',option["url"])
       //发送请求
       request.send()
  }else{//就是post请求
       // request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
       request.open('post',option["url"])
       request.setRequestHeader('Content-type',`application/${option["dataType"]}`)
       //发送请求
       request.send(JSON.stringify(option["data"]))
  }
   return new Promise((resolve,reject)=>{
        // 监听请求
       request.onreadystatechange = function(){
           if(request.readyState == 4 && request.status==200){
               // 返回数据
               let obj = JSON.parse(request.responseText)
               //成功响应出去
               resolve(obj)
          }
           //状态码 200 - 299 时候返回一个错误
           if(!/^2\d{2}$/.test(request.status)){
               reject('请求出错')
          }
      }
  })
}

调用


<script src="./promiseAjax.js"></script>
<script>
   ajax({
       url:"http://10.41.12.7:8080/shop",
       data:{id:1}
  }).then((res)=>{
       console.log(res);
  })
   ajax({
       url:"http://10.41.12.7:8080/user",
       method:"post",
       data:{username:'张三',password:'123'}
  }).then((res)=>{
       console.log(res);
  })
</script>

同源策略

概述:同源策略是netspac提出一种安全策略,他是为了防止对应的后台被无限的访问(导致对应的安全问题)。他是指 域名相同(ip地址) 端口号相同 协议相同。

同源导致的问题(跨域 cors)

1.协议不同

2.端口号不同

3.ip地址不同

4.在ftp请求 资源不同也会跨域

 

解决跨域的问题

1.后台解决 (通过设置响应头)


Access-Control-All-Origin:* //所有都可以访问
Access-Control-All-Origin-Method:* //所有请求都可以访问

2.前台解决(通过对应的请求来设置对应的后台的响应)

3.前台解决 (通过jsonp来解决跨域 后台的配合)

4.代理 (我将对应你的访问作为我对应的服务器的代理)

跨域的根本是因为http协议(不走http协议 websocket (tcp协议))

JSONP

jsonp是一种跨域的解决方式 他需要后台的配合,对应的jsonp的核心是利用了对应html中带链接属性的标签的特性 (link script iframs..不受跨域影响的特性来解决对应的跨域问题 )这个里面的js代码不是浏览器本身在操作的而是后台通过服务器渲染来操作的

 

原理:利用script标签 链接这个地址 再将我们的回调函数做为参数传入

缺点:只支持get请求 (根本上就是一个get请求)

json入门案例(百度搜索)


<input type="text">
<ul></ul>
<script>
   var ul = document.querySelector('ul')
   //通过script链接对应的地址 传入对应的回调函数
   //回调函数 console.log(res);
   function fn(res){
       ul.innerHTML = ""
       console.log(res);
       //遍历对应的res.s里面的数据 渲染到页面
       // 创建li 填入ul
       res.s.forEach(item => {
           let li = document.createElement('li')
           li.innerHTML = item
           ul.appendChild(li)
      });
  }
   //https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=miqi&cb=fn
   document.querySelector('input').oninput = function(){
       let keyWord = this.value
       var path = "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su"
       //先出创建一个script标签
       let tag =  document.createElement("script")
       tag.src = path+"?wd="+keyWord+'&cb=fn'
       document.body.appendChild(tag)
       //销毁
       tag.remove()
  }
</script>

jsonp封装


//封装对应的jsonp
static jsonp({
   url, //请求的地址
   param, //携带的参数 对象
   callback,//执行的回调函数
   callbackName //回调函数参数名
}){
   //生成一个回调函数名字
   let fnName = "fn"+ Date.now()
   //指定的回调函数名字对应的方法 加给window
   window[fnName] = callback
   //创建script标签
   var script = document.createElement('script')
   //将回调函数 cb=fn加url
   url += `?${callbackName}=${fnName}`
   //将参数对象变成
   for(let key in param){
       url+=`&${key}=${param[key]}`
  }
   //再将对应的url地址给到script标签的src
   script.src = url
   //将srcipt加给body
   document.body.appendChild(script)
   //等待script标签加载完成
   script.onload = function(){
       //将script进行销毁
       script.remove()
       //将window属性删除
       delete window[fnName]
  }
}
调用

<input type="text">
<ul></ul>
<script src="./ajax.js"></script>
<script>
   var ul = document.querySelector('ul')
   //通过script链接对应的地址 传入对应的回调函数
   //回调函数 console.log(res);
   function fn(res){
       ul.innerHTML = ""
       console.log(res);
       //遍历对应的res.s里面的数据 渲染到页面
       // 创建li 填入ul
       res.s.forEach(item => {
           let li = document.createElement('li')
           li.innerHTML = item
           ul.appendChild(li)
      });
  }
   //https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=miqi&cb=fn
   // http://api.map.baidu.com/telematics/v3/weather
   // https://api.douban.com/v2/movie/in_theaters
   document.querySelector('input').oninput = function(){
       let wd = this.value
       AjaxUtil.jsonp({
           url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
           param:{wd},
           callback:fn,
           callbackName:"cb"
      })
  }
</script>

jsonpPromise封装


function jsonp({
   url, //请求的地址
   param, //携带的参数 对象
   callbackName //回调函数参数名
}){
   return new Promise((resolve,reject)=>{
       try { //捕获异常 可能出问题代码
            //生成一个回调函数名字
           let fnName = "fn"+ Date.now()
           //指定的回调函数名字对应的方法 加给window
           window[fnName] = resolve //填入resolve在then可以获取
           //创建script标签
           var script = document.createElement('script')
           //将回调函数 cb=fn加url
           url += `?${callbackName}=${fnName}`
           //将参数对象变成
           for(let key in param){
               url+=`&${key}=${param[key]}`
          }
           //再将对应的url地址给到script标签的src
           script.src = url
           //将srcipt加给body
           document.body.appendChild(script)
           //等待script标签加载完成
           script.onload = function(){
               //将script进行销毁
               script.remove()
               //将window属性删除
               delete window[fnName]
          }
           script.onerror = function(){
               reject('当前请求错误')
          }
      } catch (error) { //处理对应的错误
           reject(error)
      }
  })
}
调用

<input type="text">
   <ul></ul>
<script src="./promiseAjax.js"></script>
<script>
   var ul = document.querySelector('ul')
//通过script链接对应的地址 传入对应的回调函数
//https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=miqi&cb=fn
// http://api.map.baidu.com/telematics/v3/weather
// https://api.douban.com/v2/movie/in_theaters
document.querySelector('input').oninput = function(){
   let wd = this.value
   jsonp({
       url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
       param:{wd},
       callbackName:"cb"
  }).then(res=>{
       ul.innerHTML = ""
       console.log(res);
       //遍历对应的res.s里面的数据 渲染到页面
       // 创建li 填入ul
       res.s.forEach(item => {
           let li = document.createElement('li')
           li.innerHTML = item
           ul.appendChild(li)
      });
  })
}
</script>

 

posted @ 2022-06-27 09:27  itxunxun  阅读(114)  评论(0)    收藏  举报