Promise和ajax同源策略

本文详细介绍了Promise的概念、特点、原理及常用方法,包括链式调用、错误处理和并发控制。同时,阐述了Ajax的同源策略,解释了为何需要跨域以及同源策略的目的。接着,深入讲解了Jsonp的工作原理、组成和实现跨域请求的方法,并展示了简单的Jsonp封装。最后,提到了CORS作为另一种跨域解决方案的角色。
摘要由CSDN通过智能技术生成

一、Promise对象

1.1、Promise概念

Promise 是es6新增的异步编程的一种解决方案,如解决回调地狱。比传统的回调函数更合理,更强大。

  • 普通回调函数和Promise代码对比

在这里插入图片描述

1.2、Promise特点

它只有两种状态,即

  • 操作成功: -----> fulfilled/resolved
  • 操作失败: -----> rejected
const p = new Promise((resolve,reject)=>{
	// 参数一: resolve参数:返回响应成功的值
    // 参数二: reject参数:返回响应失败的值
     setTimeout(()=>{
	     let n = Math.floor(Math.random()*100);
	     if (n<=30) {
	          resolve(n);
	     } else {
	          reject(n);
	     }
     })
 })
 // then()是Promise里的方法,下面会详讲
 p.then(value=>{
     console.log(value);
 })
console.log(p);

promise有三个状态:

(1) pending [待定]初始状态
(2) fulfilled [实现]操作成功
(3) rejected [被否决]操作失败

resolve作用是
将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为
resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject作用是
将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为
rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

1.3、原理

在这里插入图片描述

1.4、Promise方法

  • .then(callback)

用链式调用的方式执行回调函数.

function getTea() {
     return new Promise(function(resolve){
          setTimeout(function () {
               resolve(' 111');
          }, 1000)
    })
}

function getHotpot(){
     return new Promise(function(resolve){
     	  setTimeout(function(){
			   resolve('222');
		},2000)
    })    
}
// 通过Promise解决回调函数出现的回调地狱问题
// then()调用后返回一个Promise对象,意味着实例化后的Promise
//对象可以进行链式调用,而且这个then()方法可以接收两个函数,
//一个是处理成功后的函数,一个是处理错误结果的函数。
getTea().then(function(data){
      console.log(data)
      return getHotpot();
}).then(function(data){
      console.log(data)
})
  • .catch(callback)

主要用于捕获异步操作时出现的异常。

const p = new Promise((resolve, reject) => {
    //  修改p的状态
    reject('失败')
})

console.log(p);
// 捕获失败时的返回值
p.catch(data => {
    console.log(data);
})
  • .all()

返回一个新的promise,只有promise都成功才成功,只要有一个失败了,就都失败

const p1 = new Promise((resolve, reject) => {
     resolve('ok')
 })
const p2 = new Promise((resolve, reject) => {
     resolve('jj')
 })
const p3 = new Promise((resolve, reject) => {
     resolve('ll')
 })
const result = Promise.race([p1,p2,p3]);
// 都成功才成功
console.log(result);
  • .race()

返回一个promise,第一个完成的promise的结果状态就是最终的结果状态

const p1 = new Promise((resolve, reject) => {
     resolve('ok')
 })
 const p2 = new Promise((resolve, reject) => {
     resolve('jj')
     
// 返回第一个完成的promise的结果状态
const result = Promise.race([p1,p2]);
console.log(result);

1.5、Promise封装ajax

function promise(options){
    return new Promise((resolve,reject)=>{
        var xhr = new XMLHttpRequest();
        var params = formdata(options.data);
        if(options.type=='GET'){
            xhr.open(options.type,options.url+'?'+params,options.isAsync);
            xhr.send();
        }
        if(options.type=='POST'){
            xhr.open(options.type,options.url,options.isAsync);
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(params);
        }
        xhr.onreadystatechange = function(){
            if(xhr.readyState==4){
                if(xhr.status==200){
                    resolve(xhr.responseText)
                }else{
                    reject('错误')
                }
            }
        }

    })
}

function formdata(obj){
    var arr = [];
    for(var k in obj){
        arr.push(k+'='+obj[k])
    }
    return arr.join('&')
}


// 调用
promise({
    type:'GET',
    url:'',
    date:{},
    isAsync:true,
}).then(data=>{
    console.log(data);
    return promise({
        type:'GET',
        url:'',
        data:{},
        isAsync:true,
    })
}).then(data=>{})

二、ajax的同源策略

引言:

Ajax只能向自己的服务器发送请求。比如现在有一个A网站、有一个B网站,A网站中的 HTML 文件只能向A网站服务器中发送 Ajax 请求,B网站中的 HTML 文件只能向 B 网站中发送 Ajax 请求,但是 A 网站是不能向 B 网站发送 Ajax请求的,

2.1、什么叫做同源

同源就是两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,只要其中有一个不相同,就是不同源。

在这里插入图片描述

2.2、什么叫同源策略

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。

  • 同源策略的目的

同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指 A 网站在客户端设置的 Cookie,B网站是不能访问的。

三、jsonp跨域

所以,JSONP(json with padding)就是为了解决同源限制问题

3.1、jsonp的原理

很多标签比如src,href,都不会受到同源策略的影响

有一些标签天生就有跨域能力,比如:img,link,iframe,script

jsonp就是利用<script>的src来实现跨域获取数据的,且只支持get请求。

3.2、组成

jsonp
由两部分组成:回调函数和数据
—>回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。
—>而数据就是传入回调函数中的JSON 数据

3.3、如何利用jsonp进行跨域请求

// 前端代码
//定义函数,用来接收后端传来的字符串
function fn(data) {
     console.log(data); // 后端返回的值即fn('1212'),相当于调用前端我们定义的函数,并且把值传过来
}

// 利用script标签发送跨域请求,
// 1.php 请求地址
// callback 传递到后端的参数   fn 把定义的函数作为参数传递
<script src="1.php?callback=fn"></script>
// 后端代码
<?php
header('Content-type:text/html;charset=utf-8');
// 获取前端传来的参数,即函数
$fuct = $_GET['callback'];

$mes = '是真的吗hhhh';

// 拼接返回值,为字符串
echo $fuct.'("'.$mes.'")';

?>

3.4、简单封装jsonp

//封装jsonp,请求
function jsp(obj) {
    //参数是一个对象
    var oSci = document.createElement('script');
    //随机一个函数名
    var fn = ranFn();
    // 将传入的函数,转为window对象下
    //传入的obj中的success对应的函数就是用来接收响应字符串的函数
    window[fn] = obj.success;
    //拼接src
    oSci.src = obj.url + '?' + 'callback=' + fn + '&' + getData(obj.data);

    document.body.appendChild(oSci);
    //当script执行完毕后就删除
    oSci.onload = function () {
        this.remove();
    }

}

function ranFn() {
    //随机起函数名
    var num = Math.random();
    // console.log(num);
    return 'fn' + num.toString().replace('0.', '');
}


function getData(obj) {
    //这里的obj指的是jsonp中键名为data的对象
    var arr = [];
    for (var k in obj) {
        arr.push(k + '=' + obj[k]);
    }
    return arr.join('&');

}

//调用jsp时的格式
// jsp({
//     url: 'c.php',
//     data:{
//         a:1,
//         b:2
//     },
//     success: function (data) {
//         console.log(data);
//     }
// });

3.5、服务器端跨域

CORS:全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax请求,即克服了 Ajax 只能同源使用的限制。

  • 前端请求地址
	http://192.xx.xx.xx/myhtml/day5/1.php
  • 后端设置
Access-Control-Allow-Origin: 'http://localhost:3000'
Access-Control-Allow-Origin: '*'
header('Access-Control-Allow-Origin: *');
// 如果想设置只允许某个网站通过的话可以这样设置
// 允许test.com发起的跨域请求,其他的都不通过
header('Access-Control-Allow-Origin: http://test.com'); 

经典案例1:请求天气预报

<div>
        <br>
        省份:<input type="text" class="in1"><br><br>
        城市:<input type="text" class="in2"><br><br>
        <input type="submit" value="查询" class="in3">
    </div>
    <table>
        <thead>
            <tr>
                <th>时间</th>
                <th>温度</th>
                <th>天气类型</th>
                <th>风向</th>
                <th>湿度</th>
            </tr>
        </thead>
        <tbody>
            <!-- <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr> -->
        </tbody>
    </table>
</body>
// 调用封装好的jsonp函数
var oTby = document.querySelector('tbody');
    var oInp1 = document.querySelector('.in1');
    var oInp2 = document.querySelector('.in2');
    var oInp3 = document.querySelector('.in3');

    oInp3.onclick = function () {
        //当页面加载时触发,即调用jsp发出跨域请求
        jsp({
            url: 'https://wis.qq.com/weather/common',
            data: {
                'province': oInp1.value,
                'city': oInp2.value,
                'source': 'pc',
                'weather_type': 'forecast_1h'
            },
            success: function (res) {
                // console.log(res.data.forecast_1h);
                var resu = res.data.forecast_1h
                var str = '';
                for (var k in resu) {
                    str += `<tr>
                      <td>${getTime(resu[k].update_time)}</td>
                      <td>${resu[k].degree}</td>
                      <td>${resu[k].weather_short}</td>
                      <td>${resu[k].wind_direction}</td>
                      <td>${resu[k].wind_power}</td>
                  </tr>`;
                }
                oTby.innerHTML = str;
            }
        })
    }

function getTime(time){
    //拼接年月日小时
    var y = time.substr(0,4);
    var m = time.substr(4,2);
    var d = time.substr(6,2);
    var h = time.substr(8,2);
    return y+'-'+m+'-'+d+''+'   '+h+'时';
}

效果图
在这里插入图片描述
经典案例2:百度搜索框

// 调用jsonp函数
var oInp = document.querySelector('input');
    var oUl = document.querySelector('ul');

    oInp.oninput = function () {
        //输入框输入内容,下方产生联想词
        jsp({
            url: 'https://www.baidu.com/sugrec',
            data: {
                prod: "pc",
                wd: oInp.value,
            },
            success: function (res) {
                var str = '';

                var resu = res.g;
                console.log(typeof resu);
                // console.log(res);
                for (var i in resu) {
                    str += `<li>
                        ${resu[i].q}
                        </li>`;
                }
                oUl.innerHTML = str;
                oUl.style.display = 'block';
            }
        })
    }

效果图
在这里插入图片描述
今天的博客就到这儿了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值