Promise

简介

Promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise有三种状态:pendingfulfilledrejected

Promise对象初始化时状态为:pending(进行中)

调用resolve方法时,Promise的状态由pending变为fulfilled

调用rejected方法时,Promise的状态由pending变为rejected

1、 Promise对象的状态不受外界影响,只有异步操作的结果可以决定当前时哪一种状态,任何其他操作都无法改变这个状态。

2、 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

使用

简单的初始化一个Promise

const promise = new Promise((resolve) => {
    setInterval(() => {
        resolve('延迟2s回调');
    }, 2000);
});

上面初始化了一个Promise对象,并创建了一个异步操作:在两秒后调用resolve方法。这里仅仅是初始化了这个对象,并没有调用。继续调用这个promise对象

const promise = new Promise((resolve) => {
    setInterval(() => {
        resolve('延迟2s回调');
    }, 2000);
});

promise.then((data) => {
    console.log(data);
});

当执行代码的时候,控制台在两秒钟后打印出了“延迟2s回调”,也就是说在上面初始化Promise的resolve里面的参数回调到了下面then方法中的data参数中。简单来说就是then里面的函数,会传递到Promise中并由resolve来控制这个函数的执行时间以及执行所需要的参数并回调。

上述代码的执行过程就是Promise内部状态由pending变为fulfilled

Promise还有从pending变为rejected的过程。

const promise = new Promise((resolve, reject) => {
    setInterval(() => {
        let number = getRandomNumber();
        if(number > 5) {
            resolve('大于5');
        } else {
            reject('不大于5');
        }
    }, 2000);
});

promise.then((data) => {
    console.log('then');
    console.log(data);
}).catch((error) => {
    console.log('catch');
    console.log(error);
});

Promise中初始化了一个简单逻辑,两秒之后获得一个随机数字,该数字大于5的时候调用resolve方法,反之则调用reject方法。由上面的例子可以得知,当数字大于5的时候会在then中打印。那么当数字小于5的时候,则会在catch中打印改数字。

简单总结下来,resolve方法回调至then中,reject方法回调至catch中。

那么可以借用Promise的特点,简单的封装一个网络请求。使用resolvereject分别包装正常返回和异常返回的值和信息。

const promise = new Promise((resolve, reject) => {
            fetch(url)
                .then((response) => {
                    return response.json();
                })
                .then((responseData) => {
                    resolve(responseData);
                })
                .catch(function (error) {
                    reject(error)
                })
        })

promise.then((data) => {
    // 请求返回的数据
}).catch((error) => {
    // 请求报错
})

链式调用

通过上面的例子Promise可以理解为是一个类似延迟加载的异步回调函数,那么其实也可以用普通的方法实现Promise的功能

myPromise = (callback) => {
    setInterval(() => {
        console.log('执行完成');
        callback('随便什么数据');
    }, 2000);
}

myPromise((data) => {
    console.log(data);
})

它也会和Promise拥有同样的效果。那Promise到底能实现什么不可替代的功能呢?

假如有许多的异步操作需要执行,比如连续的三个请求,每一次请求都需要从前一个请求中获取参数,那么它的写法如下

fetch(url1).then((data1) => {
    if (data1 == 200) {
        fetch(url2).then((data2) => {
            if(data2 == 200) {
                fetch(url3) ....
                ...
            }
        })
    }
})

虽然可以实现需求,然是代码看起来并不那么友好,它庞大的层级结构使之无法轻易被修改。如果要是需要在第二个请求和第三个请求中再加入一些异步操作,那么将是不可修改的,这被称为回调地狱(Callback hell)。

使用Promise即可解决上述问题,Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。也就是说可以一直return一个Promise对象,可以一直在在后面调用then方法。如果使用Promise后上述的需求可以写为

// 分别将三个请求包装为函数
request1 = () => {
    return fetch(url1);
}
request2 = () => {
    return fetch(url2);
}
request3 = () => {
    return fetch(url3);
}
// 调用时
request1().then((data)=> {
    return request2();
}).then((data) => {
    return request3();
}).then((data) => {
    ...
}).catch();

只需要在then中调用下一个Promise,上一个Promise中回调的数据即可传递下去。

关于回调地狱(Callback hell)的问题也可以使用async/await解决,类似的代码如下

task() async {
   try{
    String id = await request1();
    String userInfo = await request2();
    await request3();
    //执行接下来的操作   
   } catch(e){
    //错误处理   
    print(e);   
   }  
}

相关API

all

Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([promise1, promise2, promise3]);

p的状态由promise1promise2promise3决定,分成两种情况。

(1)只有promise1promise2promise3的状态都变成fulfilledp的状态才会变成fulfilled,此时promise1promise2promise3的返回值组成一个数组,传递给p的回调函数。

(2)只要promise1promise2promise3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

注意,如果作为参数的 promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()catch方法。

race

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([promise1, promise2, promise3]);

上面代码中,只要有任何一个promise改变状态,那么p的状态也会跟着改变。也就是说最快改变状态的promise会让其他promise不会回调。

可以通过这个方法来完成一个请求超时功能

const p = Promise.race([
  fetch(url),
  new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);

即当5s内请求没有返回结果,就返回请求超时。

参考链接

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容