期望在身上,梦想在流浪 切换

关于promise、async await 、axios的详解

在开发项目中,我们经常需要使用ajax发起异步请求获取数据,但是当我们需要从得到的数据中用于请求下一个异步任务时,就会有多个回调函数嵌套在里面,这个时候代码阅读性就会变得很差,维护成本也相对较高,这种回调函数层层嵌套我们称之为回调地狱。

回调地狱:

$.ajax({
    url: 'data1.json',
    type: 'GET',
    success: function (res) {
        $.ajax({
            url: res.url, // 将 第一个ajax请求成功得到的res 用于第二个ajax请求
            type: 'GET',
            success: function (res) {
                $.ajax({
                    url: res.url,  // 将第二个ajax请求成功得到的res 用于第三个ajax请求
                    type: 'GET',
                    success: function (res) {
                        console.log(res)   // {url: "this is data3.json"}
                    },
                    error: function(err) {
                        console.log(err)
                    }
                })
            },
            error: function(err) {
                console.log(err)
            }
        })
    },
    error: function(err) {
        console.log(err)
    }
})

  上面出现多个回调函数的嵌套,可读性较差,我们通常使用Promise来优化,使代码从回调地狱中解脱出来

 

Promise:

什么是promise,在《ES6标准入门》一书中,详细介绍了Promise

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且强大,它最早由社区提出并实现,ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。

Promise对象有以下两个特点:

(1)对象的状态不受外界影响,promise对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是promise这个名字的由来“承若”;
(2)一旦状态改变就不会再变,任何时候都可以得到这个结果,promise对象的状态改变,只有两种可能:从pending变为fulfilled,从pending变为rejected。这时就称为resolved(已定型)。如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果,这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。


关于onFulfilled、onRejected状态,MND是这样解释的

onFulfilled

当Promise变成接受状态(fulfillment)时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,即接受的最终结果(the fulfillment  value)。如果传入的 onFulfilled 参数类型不是函数,则会在内部被替换为(x) => x ,即原样返回 promise 最终结果的函数

onRejected

当Promise变成拒绝状态(rejection )时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,,即拒绝的原因(the rejection reason)。

上述文档中我们可以知道,当我们new一个Promise对象中,Promise会帮我们执行里面的异步操作,执行后的异步操作会通过Promise中resolve和reject参数传递出去,传递出去的数据我们可以在then中进行操作。

var pro0 = function (state) {
        return new Promise(function (resolve, reject) {
            if(state == true) {
                setTimeout(function () {
                    resolve('第一个异步任务');

                }, 1000)
            }else {
                setTimeout(function () {
                    reject('失败的异步任务');

                }, 1000)
            }
        })
    }

//当state为true时
pro0(true).then(
(data)=>{console.log(data)},//1s后输出"第一个异步任务"
(err) =>{console.log(err)}) //未输出

//当state为false时
pro0(false).then(
(data)=>{console.log(data)}, //"未输出"
(err) =>{console.log(err)}) //1s后输出"失败的异步任务"
 

上面的代码我们基本清楚了Promise的原理以及用法,那么Promise是怎么解决回调地狱的呢?

 

Promise链式调用:

事实上,Promise中的then方法除了可以接收异步请求得到的数据时,还能返回一个新的promise对象,返回来的promise对象可以接着在下一个then中进行操作,这就是所谓的链式调用

var pro0 = function (state) {
        return new Promise(function (resolve, reject) {
            if(state == true) {
                setTimeout(function () {
                    resolve('第一个异步任务');

                }, 1000)
            }else {
                setTimeout(function () {
                    reject('失败的异步任务');

                }, 1000)
            }
        })
    }

    var pro1 = function(){
        return new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve('第二个异步任务')
            },1000)
        })
    }

//当state为true时
pro0(true).then(
(data)=>{console.log(data);return pro1()},//1s后输出"第一个异步任务"
(err) =>{console.log(err);return pro1()}//未输出
).then((data)=>{console.log(data)})//2s后输出"第二个异步任务"
//当state为false时
pro0(false).then(
(data)=>{console.log(data);return pro1()},//未输出
(err) =>{console.log(err);return pro1()}//1s后输出"失败的异步任务"
).then((data)=>{console.log(data)})//2s后输出"第二个异步任务"
 

上面的代码中,我们在pro0的then里返回了一个pro1函数,在下一个then中接收到了pro1函数所传递出来的值

 

async await

async/await可以看做是promise中then函数的优化,then函数是链式调用,一点接一点,是一种从左到右的横向写法;而async/awiat是从上到下的顺序执行,就像写同步代码一样,更符合编程习惯

var pro0 = function (state) {
    return new Promise(function (resolve, reject) {
        if(state == true) {
            setTimeout(function () {
                resolve('第一个异步任务');

            }, 1000)
        }else {
            setTimeout(function () {
                reject('失败的异步任务');

            }, 1000)
        }
    })
}

var pro1 = function(){
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve('第二个异步任务')
        },1000)
    })
}

 async function getData () {
console.log(await pro0(true))//1s后输出"第一个异步任务"
console.log(await pro1())//2s后输出
}
 

上面代码中我们为getDate()函数声明了async,这样当我们执行这个getData()函数的时候,里面的promise对象就会一个接一个的执行(await等待);例外,在async/await中,await只能接收resolve对象,如果想要接收reject对象,只能使用传统的try catch去处理。

 

例外说一下axios,在实例项目开发中,我们经常使用axios配合async/await去发起异步请求处理数据,其实axios可以看作是基于promise的一种请求方式,与ajax相比,它解决了ajax回调地狱的问题,两者的使用方式基本一样。

axios({
            url: 'xxx',
            method: 'get',
            responseType: 'json', // 默认的
            data: {
                //'a': 1,
                //'b': 2,
            }
        }).then(function (response) {
            console.log(response);
            console.log(response.data);
        }).catch(function (error) {
            console.log(error);
        })


$.ajax({
            url: 'xxx',
            type: 'get',
            dataType: 'json',
            data: {
                //'a': 1,
                //'b': 2,
            },
            success: function (response) {
                console.log(response);
            }
        })

 

 

posted @ 2020-04-26 21:41  帅哥别  阅读(2629)  评论(0)    收藏  举报