关于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);             }         })

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM