前言

Promise,用于解决回调地域带来的问题,将异步操作以同步的操作编程表达出来,避免了层层嵌套的回调函数。

什么是 Promise

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

Promise特性

  • promise 对象代表一个异步操作,有三种状态:pending、fulfilled、reject
  • 任何其他状态都无法改变这个状态。这也是 Promise 这个名字的由来。'承诺'表示其他手段无法改变它的状态。

Promise 的出现解决什么问题

promise其实就是一个异步编程方案,在 promise 出现之前总会遇到所谓的'回掉地域'的嵌套代码

    step(1, function() {
        step(2, function() {
            step(3, function() {
                ……….
            })
        })
    })

都知道这种"回调地狱",是一种很让人恼火的代码书写格式,嵌套多层之后会让人阅读起来怀疑人生的。但是这种"回调地狱"真的就只有格式的问题嘛?显然不是。

引用例子

一个来自《YDKJS》的例子:一个程序员开发了一个付款的系统,它良好的运行了很长时间。突然有一天,一个客户在付款的时候信用卡被连续刷了五次。这名程序员在调查了以后发现,一个第三方的工具库因为某些原因把付款回调执行了五次。在与第三方团队沟通之后问题得到了解决。

上面的例子就是一个 信任问题 回调函数的方式会引发很多信任问题,例如重复调用,调用太晚等等问题。那么promise怎么解决上述两个问题的呢?

Promise意义

  • 可读性
    首先是 Promise 的 then 方法,支持我们在回调写在 then 方法中,让我们在日常开发中可以很清楚的看到,比如上面的代码就可以改写成
     Promise.resolve(1).
     .then(step => ++setp)
     .then(step => ++setp)
     .then(step => ++setp)
 ...
  • Promise 承诺的严谨性
    它与普通的回调方式的区别在于

普通方式,回调成功之后的操作直接写在了回调函数里面,而这些操作的调用是由第三方控制

Promise方式 回调只负责成功之后的通知,而回调成功之后的操作放在 then 的回调函数里面,由 Promise 精确控制。

注意 Promise 的状态不可逆。一旦发生改变就没有办法改变成任何一种状态。Promise 只能是异步的,所以不会出现异步的同步调用。

Promise缺点

  • 无法取消 Promise 一旦新建它就会立即执行,无法中途取消
  • 如果不设置回调函数,Promise 内部抛出的错误不会反应到外部。
  • 当处于 pending 状态,无法得知目前进行到哪一阶段(刚开始还是快结束)

如何使用Promise

Promise 对象是一个构造函数,用来生成 Promise 实例

Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject,这两个参数也函数,由 JavaScript 提供,不需要自己添加

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。但一般不建议给then加两个参数,建议使用.then完成resolved状态的操作,使用.catch完成rejected的操作。
像这样:

    const promise = new Promise( (resolve,reject) => {
        resolve('ok');
        reject('error')
    })
    promise.then(res => {
        console.log(res)
    }).catch(err => {
        console.log(err)
    })

还可以用promise实现ajax的操作:

const getJSON = function(url){
        const promise = new Promise((resolve,reject) => {
            const handler = function(){
                if(this.readyState !== 4){//这两个if语句主要用来判断请求是否成功
                    return;
                };
                if(this.status === 200){
                    resolve(this.response)//这是成功请求后,将返回的数据传到回调函数中
                }else{
                    reject(new Error(this.statusText))//这是失败后,将原因返给catch
                }
            };
            const xmlHttp = new XMLHttpRequest();//声明一个XMLHttpRequest对象的实例
            xmlHttp.open("get", url);//设置要发送的方法和地址
            xmlHttp.onreadystatechange = handler;//在这里调用上面定义的handler
            xmlHttp.responseType = "json";
            xmlHttp.setRequestHeader("Accept", "application/json");//设置请求头,规定接受json类型的数据
            xmlHttp.send();//真正的发送请求
        });
        return promise;
    };
    getJSON("url").then( res => {
        //成功后的操作
    }).catch(err => {
        //失败后的提示
    })

Promise可以嵌套使用,就是将一个Promise实例作为另一个Promise实例的resolve方法的参数传入。

说说then方法,这个方法是定义在Promise的原型上的,then方法返回的是一个新的Promise实例,因此可以采用链式写法,即then方法后面调用另一个then方法。

再来说几个Promise常用的api吧!

Promise.prototype.finally():

Finally方法用于不管promise对象的最后状态如何,都会执行的操作

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

Promise.resolve():

  • 这个方法用来将参数转变成Promise对象
  • 参数是一个Promise实例:不改动
  • 参数是一个thenable对象:会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
  • 参数不是具有then方法的对象,或根本就不是对象:返回一个新的Promise对象,状态为resolved
  • 不带有任何参数:直接返回一个ersolved状态的Promise对象

Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

Promise.all():

    const p = Promise.all([p1, p2, p3]);

用于将多个Promise实例,包装成一个新的Promise实例。这个方法接收一个数组作为参数,且都是Promise实例,如果不是,就会先调用Promise.resolve方法。
注意:
只有当数组中的实例的状态都是fulfilled,p才会变成fulfilled,此时,p1,p2,p3的返回值组成一个数组,传递给p的回调函数。
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race():
和all方法类似,也是讲多个Promise实例包装成一个。
但不一样的是,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

在实际开发中,我们总希望让同步函数同步执行,异步函数异步执行,但如果同步函数想用Promise来做处理,能否实现同步呢?答案是肯定的。
这就要说到Promise.try()方法了

    const f = () => console.log('now');
    Promise.try(f);
    console.log('next');
// now// next


图片


凃老师
39 声望3 粉丝