day40-Promise

回调函数

概念:将一个函数当做参数传入另一个函数的时候,这个函数就叫回调函数。

我们之前用过很多次回调函数,比如:数组方法map、filter等;运动函数中处理运动结束传入的函数;分页插件中使用插件的时候执行的函数。。。包括封装的ajax中,请求成功以后执行的success函数。都是回调函数。

为什么要使用回调函数?

当我们执行一些异步操作的时候,需要在操作完成以后,做另外的一些事情,但是我们又没有办法预知这个异步操作什么时候结束,此时只能使用回调函数的形式来解决这个问题。

回调地狱

我们在封装ajax的时候,发现:请求成功后的值不能直接返回给调用者,而需要在其内部执行一个回调函数。如果在请求一次后需要再次请求,那么,也就是在回调函数中需要再次调用ajax,再次传入回调函数,次数多了以后,代码是下面这个样子:

回调地狱

 这样的代码难以阅读和维护,这是著名的”回调地狱“。

ajax({
    url: 'http://localhost:8888/test/first',
    dataType: 'text',
    success: res => {
        console.log(res);
        // 测试1结束
        // 发送测试请求2
        ajax({
            url: 'http://localhost:8888/test/second',
            success: res => {
                console.log(res);
                // 测试2结束
                // 发送测试请求3
                ajax({
                    url: 'http://localhost:8888/test/third',
                    data: {
                        name: '张三',
                        age: 12
                    },
                    success: res => {
                        console.log(res);
                    }
                })
            }
        })
    }
})

这种嵌套多了以后,就会形成回调地狱。

es6为了解决这个问题,所以新增了promise语法。

Promise

promise是承诺的意思,表示他承诺帮你做这件事情,然后将结果给你。

语法:

new Promise(function (resolve, reject) {
  // resolve 表示成功的回调
  // reject 表示失败的回调
}).then(function (res) {
  // 成功的函数
}).catch(function (err) {
  // 失败的函数
})

在promise构造函数中,提供了两个参数,分别表示执行成功和失败的回调函数,执行成功调用resolve,失败调用reject即可,具体resolve和reject的执行,分别在then和catch中。

这样可以将回调函数变成链式结构,从而解决了回调地狱的问题。

例:

var p = new Promise(function(resolve, reject){
    // 测试请求1
    ajax({
        url: 'http://localhost:8888/test/first',
        dataType: 'text',
        success: res => {
            resolve(res)
        },
        error: res => {
            reject('请求1错误')
        }
    })
})
​
p.then(function(res){
    console.log(res);
    // 在这里第一次请求结束
    // 发送第二次请求
    var p1 = new Promise(function(resolve, reject){
        ajax({
            url: 'http://localhost:8888/test/second',
            success: res => {
                resolve(res)
            },
            error: res => {
                reject('请求2错误')
            }
        })
    })
​
    return p1
}).then(function(res){
    console.log(res);
    // 测试请求2结束
    // 发送第3个请求
    var p2 = new Promise(function(resolve, reject){
        ajax({
            url: 'http://localhost:8887/test/third',
            data: {
                name: '张三',
                age: 12
            },
            success: res => {
                resolve(res)
            },
            error: res => {
                reject('请求3错误')
            }
        })
    })
​
    return p2
}).then(res => {
    console.log(res);
}).catch(res => {
    console.log(res);
})

使用说明:

  1. promise的then可以直接写在对象后面

  2. 如果在promise的then里面返回一个promise对象,那么里面的promise的then可以跟在外面的promise的then后面

补充:then和catch不会同时触发,也就是说,只要一个then出错了,执行最底下的catch就行,所以也就可以连续写多个then,一个catch就行。

promise成功解决了回调地狱的问题,但是这对于我们一个追求完美的攻城狮来说,远远不够,我们希望可以再次优化。

将ajax封装到promise中:将sendAjax中的success换成resolve,将sendAjax中的error换成reject

调用方式:

ajaxPromise({
    url: 'http://localhost:8888/test/first',
    dataType: 'text'
}).then(res => {
    console.log(1, res);
    // 第一个请求结束
    return ajaxPromise({
        url: 'http://localhost:8888/test/second',
    })
}).then(res => {
    console.log(2, res);
    // 第2个结束
    return ajaxPromise({
        url: 'http://localhost:8888/test/third',
        data: {
            name: '张三',
            age: 12
        }
    })
}).then(res => {
    console.log(3, res);
})

ASYNC/AWAIT

es7提供了async/await来编写异步代码,是回调地狱的终极解决方案。

他可以将异步代码写的和同步代码一样。

语法:

async function fn() {
    const res = await promise对象
}

只要是一个 promise 对象,那么我们就可以使用 async/await 来书写

例:

async function fn(){
    var a = await ajaxPromise({
        url: 'http://localhost:8888/test/first',
        dataType: 'text'
    })
    // await可以将promise对象中调用resolve的时候传递参数等到出来
​
    console.log(a);
}
​
fn()

使用说明:

  1. async修饰的函数,需要调用的话,就正常调用

  2. await必须包在async修饰的函数中

将async和封装的promise结合起来封装:

async function fn(){
    // 发送第一个请求
    var res1 = await ajaxPromise({
        url: 'http://localhost:8888/test/first',
        dataType: 'text'
    })
    console.log(1, res1);
    // 发送第2个请求
    var res2 = await ajaxPromise({
        url: 'http://localhost:8888/test/second'
    })
    console.log(2, res2);
    // 发送第3个请求
    var res3 = await ajaxPromise({
        url: 'http://localhost:8888/test/third',
        data: {
            name: '张三',
            age: 12
        }
    })
    console.log(3, res3);
}   
​
fn()

跨域

正常情况下,我们使用ajax请求的数据都在自己的服务器上。但在一些特定的场景中,我们需要获取到别人的服务器上的数据,也就是在自己的服务器中的ajax要请求到别人的服务器的网址,这就是跨域。但是浏览器是不允许这样操作的,因为浏览器有同源策略。

同源策略:所谓同源,就是指域名、协议、端口都相同。比如说:在自己的localhost域名下请求www.baidu.com下的内容,这样的协议首先就不同,自己的是http,百度的是https,所以会被同源策略限制。

如何解决跨域?

1.借助当前服务器中的后端语言代替请求
    自己的页面发送ajax -> 自己服务器中的某个页面 -> 让后端(nodejs/php/java)写爬虫 -> 请求数据 -> 数据回来以后,给到自己的ajax就好
2.借助当前服务器代替自己去请求 - proxy(服务器代理)
3.给目标地址设置允许跨域的响应头 - cors
4.利用某些标签在发送请求的时候,就不会受到同源策略的限制 - 动态创建标签案发起请求 - jsonp

jsonp的跨域原理:利用某些标签在发送请求的时候,不受同源策略的限制

例:
        img引入别的网站的图片链接 - 会把请求回来的数据当做图片解析
        link标签引入别的网站的样式文件 - 会把请求回来的数据当做css解析
        iframe引入别的网站地址 - 会把请求回来的数据当做html文档解析
        script标签引入别的网站的js文件 - 会把请求回来的数据当做js代码解析

 jsonp利用script标签引入地址的时候,不受同源策略的限制,发送请求
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值