ES6-promise


Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。Promise对象有以下两个特点:
1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
--来自官方文档

Javascript是一种单线程的语言,所有的代码必须按照所谓的“自上而下”的顺序来执行。本特性带来的问题就是,一些将来的、未知的操作,必须异步实现。之前我们想要执行一些比较复杂的异步操作,就会嵌套很多层回调函数,引入ES6中Promise这个概念,处理起来就比较简单了。

//原始方法
async1(function(){
    console.log('async1执行完毕');
    async2(function(){
        console.log('async2执行完毕');
        async3(function(
            console.log('async3执行完毕');
            async4(funciton(){
                console.log('async4执行完毕');
                async5(function(){
                    console.log('async5执行完毕');
                    console.log('流程执行完毕');  
                });
            });
        )); 
    });
});

是不是看迷糊了,在真正的项目开发中也许会遇到更加复杂的执行情况。

//ES6-Promise
Promise.then(() => {
    console.log('async1执行完毕');
}).then(() => {
    console.log('async2执行完毕');
}).then(() => {
    console.log('async3执行完毕');
}).then(() => {
    console.log('async4执行完毕');
}).then(() => {
    console.log('async5执行完毕');
    console.log('流程执行完毕');
});

这样看是不是清晰多了。
ES6-Promise中有以下几个操作方法,链式操作、resolverejectcatchallrace

一、链式操作

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

let runAsync1 = () => {
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('异步任务1执行完成');
            resolve('数据1');
        }, 1000);
    });
    return p;            
}
let runAsync2 = () =>{
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('异步任务2执行完成');
            resolve('数据2');
        }, 2000);
    });
    return p;            
}
let runAsync3 = () =>{
    let p = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('异步任务3执行完成');
            resolve('数据3');
        }, 2000);
    });
    return p;            
}
runAsync1().then((data) => {
    console.log(data);
    return runAsync2();
}).then((data) => {
    console.log(data);
    return runAsync3();
}).then((data) => {
    console.log(data);
});

这样能够按顺序,每隔两秒输出每个异步回调中的内容,在runAsync2中传给resolve的数据,能在接下来的then方法中拿到。以上代码的执行结果为:

而我们更改调用顺序,并在最后一步,返回‘执行结束’字符串。

runAsync1().then((data) => {
    console.log(data);
    return runAsync3();
}).then((data) => {
    console.log(data);
    return runAsync2();
}).then((data) => {
    console.log(data);
    return '执行结束';
}).then((data) => {
    console.log(data);
});

执行结果如下:

这样我们就可以很方便、清晰的去决定我们的程序的执行顺序,达到预计想要的结果。

二、resolve 操作

resolve的作用就是把Promise的状态置为resolved,这样我们在then中就能捕捉到,然后执行“成功”情况的回调。这里就不做细展示了,在之前的例子中都可以看到详细的代码结构。

三、reject 操作

reject和resolve类似,reject的作用就是把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。但是resolve是必须的参数,reject不是必须的。

let compare = (num1,num2) => {
    var p = new Promise((resolve, reject) => {
        if (num1 < num2) {
            resolve('resolved:'+num1+'<'+num2);
        } else if (num1 === num2) {
            resolve('resolved:'+num1+'='+num2);
        } else {
            reject('rejected:'+num1+'>'+num2);
        }
    });
    return p;            
}

compare(7,10).then((data) => {
    console.log(data);
},(err) => {
    console.log(err);
});

compare(10,10).then((data) => {
    console.log(data);
},(err) => {
    console.log(err);
});

compare(10,7).then((data) => {
    console.log(data);
},(err) => {
    console.log(err);
});

如以上程序如果第一个参数小于等于第二个参数,则Promise的状态为成功;如果第一个参数大于第二个参数,则Promise的状态为失败。如图:
四、catch 操作

catch的一个作用与reject类似。如:

compare(10,7).then((data) => {
    console.log(data);
}).catch((err) => {
    console.log(err);
});

结果:

在执行resolve的回调时,如果抛出异常了(代码出错了),那么就会报错卡死js。如:

compare(10,7).then((data) => {
    console.log(data);
    console.log(msg);
},(err) => {
    console.log(err);
})

执行结果:

而catch的另一个作用就是在执行resolve的回调时,如果抛出异常了(代码出错了),js不会报错卡死,而是会进到这个catch方法中。如:

compare(7,10).then((data) => {
    console.log(data);
    console.log(msg);
}).catch((err) => {
    console.log(err);
});

执行结果:
五、all 操作

all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。all里的所有个异步操作的并行执行的,等到它们都执行完后才会进到then里面,在then里面我们会接受到一个数组就是all的异步操作依次得到的值。如:

Promise.all([
    runAsync1(), runAsync2(), runAsync3()
]).then(function(data){
    console.log(data);
});

执行结果:
六、race 操作

all方法的执行原理是所有异步操作都执行完才会进入then操作,也就是要等最慢的一个执行完才会进入then操作;而race方法的执行原理则是最快的一个异步操作执行完就立即进入then操作,其他异步操作会继续进行但不会进入then操作。如下:

Promise.race([
    runAsync1(), runAsync2(), runAsync3()
]).then(function(results){
    console.log(results);
});

执行结果:

只有不断找寻机会的人才会及时把握机会。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容