其他分享
首页 > 其他分享> > promise和jsonp

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设计为异步的

image-20220624094455211

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

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

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

示例
// 使用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来解决回调地狱

image-20220624114507204

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会让当前的主线程等待 (上锁)当你执行完成(成功了或者失败了)才放行(解锁)

image-20220624115320301

//使用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请求 资源不同也会跨域

image-20220624155325085

解决跨域的问题

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>

标签:console,log,script,url,res,promise,jsonp
来源: https://www.cnblogs.com/2323-qq/p/16417268.html