文章
问答
冒泡
前端学习笔记-Promise

在实际的使用中,有非常多的应用场景我们不能立即知道应该如何继续往下执行。最常见的一个场景就是ajax请求。通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。

var url = 'https://test.xxxx.com/api/v1'
var result;
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function(){
    result = XHR.response
}

在ajax的原生实现中,利用了onreadystatechange事件,当该事件触发并且符合一定条件时,才能拿到想要的数据,之后才能开始处理数据。
这样做看上去并没有什么麻烦,但如果这个时候,我们还需要另外一个ajax请求,这个新ajax请求的其中一个参数,得从上一个ajax请求中获取,这个时候我们就不得不等待上一个接口请求完成之后,再请求后一个接口,如下:

var url = '[https://test.xxxx.com/api/v1](https://test.xxxx.com/api/v1)'
var result;
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function(){
    result = XHR.response
    var url2 ='[https://test.xxxx.com/api/v1?code=' +](https://test.xxxx.com/api/v1?code='+) result.code
    var XHR2 = new XMLHttpRequest();
    XHR2.open('GET', url, true);
    XHR2.send();
}

当我们想要确保某代码在谁谁之后执行时,我们可以利用函数调用栈,将我们想要执行的代码放入回调函数中。

/**回调函数**/
function want(){
    console.log('这是想要执行的代码');
}
 
function fn(want){
    want && want();
}
fn(want);

如果浏览器已经支持了原生的Promise对象,那么我们就知道,浏览器的js引擎里已经有了Promise队列,这样就可以利用Promise将任务放在它的队列中去。

function want(){
    console.log('这是想要执行的代码');
}
function fn(want){
    return new Promise((resolve, reject) => {
        if(typeof want=='function'){resolve(want)}
        else{reject(`TypeError:${want}is not a function`)}
    })
}
fn(want).then(res => {
    want();
})
fn('123').catch(err => {
    console.log(err)  //TypeError: '123'is not a function
})

一、 Promise对象有三种状态


  • pending: 等待中,或者进行中,表示还没有得到结果
  • resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
  • rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行

这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆。在Promise对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理Promise的状态变化。

new Promise((resolve, reject) => {
    if(true){resolve()}
    else{reject()}
})

二、 Promise对象中的then方法

可以接收构造函数中处理的状态变化,并分别对应执行。then方法有2个参数,第一个函数接收resolved状态的执行,第二个参数接收reject状态的执行。

function fn(want){
    return new Promise((resolve, reject) => {
        if(typeof want=='function'){resolve(want)}
        else{reject(`TypeError:${want}is not a function`)}
    })
}
fn((a,b)=>a+b).then(res=>{}, err=>{})

then方法的执行结果也会返回一个Promise对象。因此我们可以进行then的链式执行,这也是解决回调地狱的主要方式。

function fn(want){
    return new Promise((resolve, reject) => {
        if(typeof want=='function'){resolve(want)}
        else{reject(`TypeError:${want}is not a function`)}
    })
}
fn().then(res=>{}).then(null, err=>{})


then方法的执行结果也会返回一个Promise对象。因此我们可以进行then的链式执行,这也是解决回调地狱的主要方式。

三、Promise中的数据传递

var fn = function(num) {
    return new Promise(function(resolve, reject) {
        if (typeof num == 'number') {
            resolve(num);
        } 
        else {
            reject('TypeError');
        }
    })
}
fn(2).then(function(num) {
    console.log('first: ' + num);
    return num + 1;
})
.then(function(num) {
    console.log('second: ' + num);
    return num + 1;
})
.then(function(num) {
    console.log('third: ' + num);
    return num + 1;
});
// 输出结果
first: 2
second: 3
third: 4

四、Promise.all

当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。
Promise.all接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法

var url = '[https://hq.tigerbrokers.com/fundamental/finance\_calendar/getType/2017-02-26/2017-06-10](https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10)';
var url1 = '[https://hq.tigerbrokers.com/fundamental/finance\_calendar/getType/2017-03-26/2017-06-10](https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-03-26/2017-06-10)';

function renderAll() {
    return Promise.all([getJSON(url), getJSON(url1)]);
}

renderAll().then(function(value) {
    // 建议大家在浏览器中看看这里的value值
    console.log(value);
})

五、 Promise.race

与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数,不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了

var url = '[https://hq.tigerbrokers.com/fundamental/finance\_calendar/getType/2017-02-26/2017-06-10](https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10)';
var url1 = '[https://hq.tigerbrokers.com/fundamental/finance\_calendar/getType/2017-03-26/2017-06-10](https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-03-26/2017-06-10)';

function renderAll() {
    return Promise.all([getJSON(url), getJSON(url1)]);
}

renderAll().then(function(value) {
    console.log(value);
})

关于作者

小乙哥
学海无涯,回头是岸
获得点赞
文章被阅读