2

1 是什么

先直接上图,打印一下Promise对象,观察下Promise是什么

console.dir(Promise)

Promise对象
可以知道,Promise是一个构造函数,有着reject、resolve函数。prototype有then、catch等方法,说明了只要是Promise对象都会有这两个方法。

Promise构造函数是传入一个函数

2 怎么用

var promise = new Promise((resolve, reject) => {
    setTimeout(function () {
        console.log('执行完成');
        resolve('随便什么数据');
    }, 2000);
});

result:
执行完成

传入的函数有两个参数:resolve、reject,分别表示异步操作执行成功后的回调函数和异步操作失败后的回调函数。其实这里用“成功”和“失败”来描述并不准确,按照标准来讲,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。不过在我们开始阶段可以先这么理解,后面再细究概念。

运行以上代码,发现promise并没有调用,只是new了一个Promise,对应的传入函数的代码就已经执行了。因此,我们通常都是把Promise包在一个函数中,在需要的时候才去运行这个函数,如:

function f() {
    var promise = new Promise((resolve, reject) => {
        setTimeout(function () {
            console.log('执行完成');
            resolve('随便什么数据');
        }, 2000);
    });
    return promise
}

f()

result:
执行完成

这时引出两个问题。为什么需要大费周章的包装这样的一个函数?resolve有什么用?

2.1 为什么需要引入

f().then(function(data){
    console.log(data);
    //后面可以用传过来的数据做些其他操作
    //......
});

在f()的返回上可以直接调用then方法,then接收一个参数,是函数,并且会拿到我们在f中调用resolve时传入的参数。运行这段代码,会在2秒后输出“执行完成”,紧接着输出“随便什么数据”。

这时,我们恍然大悟了,原来then调用的function相当于我们之前写的回调函数,相当于是这种形式:

function runAsync(callback){
    setTimeout(function(){
        console.log('执行完成');
        callback('随便什么数据');
    }, 2000);
}

runAsync(function(data){
    console.log(data);
});

那使用Promise有什么好处呢?我们不妨考虑一个问题,如果callback函数也是一个异步操作,而且执行完后也需要有相应的回调函数,可能会变成 runAsync(function(data,function(data){}){.....})。看起来十分丑陋,假如使用Promise代码就不会这么丑陋了~

Promise的优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。

2.2 链式操作的用法

所以,从表面上看,Promise只是能够简化层层回调的写法,而实质上,Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的:

runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});


function runAsync1(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务1执行完成');
            resolve('随便什么数据1');
        }, 1000);
    });
    return p;            
}
function runAsync2(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务2执行完成');
            resolve('随便什么数据2');
        }, 2000);
    });
    return p;            
}
function runAsync3(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('异步任务3执行完成');
            resolve('随便什么数据3');
        }, 2000);
    });
    return p;            
}

result:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
异步任务3执行完成
随便什么数据3

我们可以通过链式编程避免了包含多函数回调的情况,当然并不是都需要return Promise对象,你也可以返回其他数据类型,在后面的then中就能直接直接接收到数据了,比如:

runAsync1()
.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return '直接返回数据';  //这里直接返回数据
})
.then(function(data){
    console.log(data);
});

result:
异步任务1执行完成
随便什么数据1
异步任务2执行完成
随便什么数据2
直接返回数据

2.3 reject用法

前面我们一直都是使用resolve函数,并没有使用reject函数。resolve函数是表示了“执行成功”的回调,reject函数表示“执行失败”的函数。

function runAsync1() {
    var p = new Promise(function (resolve, reject) {
        //做一些异步操作
        setTimeout(function () {
            console.log('异步任务1执行完成');
            // resolve('随便什么数据1');
            reject("error")
        }, 1000);
    });
    return p;
}

runAsync1().then((data) => {
    console.log('resolve');
    console.log(data)
}, (error, data) => {
    console.log('rejected');
    console.log(error)
})

result:
异步任务1执行完成
rejected
error

需要注意的是,只要执行reject或者resolve,后面的就不会执行了,如:

function runAsync1() {
    var p = new Promise(function (resolve, reject) {
        //做一些异步操作
        setTimeout(function () {
            console.log('异步任务1执行完成');
            resolve('随便什么数据1');
            reject("error")
        }, 1000);
    });
    return p;
}

因为resolve在reject的前面,所以只会执行resolve,不会执行reject。

3 总结

  • Promise是一个对象
  • 引入是为了消除多重回调函数
  • Promise还有很多方法没有介绍(catch、finally、success、fail)

参考文献

ECMAScript6入门
大白话讲解Promise(一)
ECMAScript6入门

署名

广州芦苇科技Java开发团队

芦苇科技-广州专业互联网软件服务公司

抓住每一处细节 ,创造每一个美好

关注我们的公众号,了解更多

想和我们一起奋斗吗?lagou搜索“ 芦苇科技 ”或者投放简历到 server@talkmoney.cn 加入我们吧

关注我们,你的评论和点赞对我们最大的支持


广州芦苇科技后台
55 声望5 粉丝

抠细节的工程师思想