浅析Promise

什么是Promise?

Promise是ES6提供的一种解决异步编程的方案。web

Promise的本质是一个构造函数,咱们能够使用new Promise来建立Promise实例对象,利用Promise对象的方法进行异步编程。ajax


为何要使用Promise?

   1. Promise定义回调函数的方式更灵活。sql

使用纯回调函数解决异步问题,回调函数必须在一开始就被指定,而Promise的回调函数能够在启动了异步任务后指定,甚至能够在异步任务结束后指定。编程

   2. Promise能够解决回调函数由于嵌套形成的回调地狱。promise

若是后面的异步操做,须要拿到前面异步操做的数据后才能执行,使用纯回调函数,会出现层层嵌套的问题。形成的结果是代码不易阅读,不易维护。bash

Promise的三种状态——pending、resolved、rejectedkoa

新建一个Promise对象时,初始的状态为pending(等待中),调用resolve(),状态变为resolved/fullfilled(成功)。调用reject(),状态变为rejected(失败)。ssh

状态一旦改变,就没法再改变。也就是说,若是已经调用了resolve()和reject()中任意一个函数,再进行调用,Promise状态不会再发生改变。异步


Promise的执行流程


简述:一开始,咱们经过new Promise()建立一个Promise对象,此时的状态为pending。promise的参数接收两个函数,分别是resolve和reject。在成功的时候调用resolve(),在失败的时候调用reject()。resolve()和reject()中的任意一个被调用后,promise的状态发生对应的改变(resloved/rejected)。resolve()和reject()的调用是promise状态的标识,也是后续异步操做的指路灯。只有在状态确认后,才能进行对应的成功/失败的异步操做,也就是执行then/catch中的回调函数。执行完回调函数后,会返回一个新的Promise对象。ide


Promise代码例子

const promise=new Promise((reslove,reject)=>{  //执行器函数(executor)--> 同步回调函数    setTimeout(()=>{        if(Date.now()%2==0){            //成功时调用resolve()            reslove('success '+Date.now());  //reslove和reject中均可以传入值,且只能传入一个值        }else{            //失败时调用reject()            reject('failed '+Date.now());        }    },1000)})


//then和catch会接收在resolve和reject中传入的数据

//1. then能够接收resolve和reject的值(resolve在前,reject在后)promise.then(value=>{    console.log(value);  //onresolved回调函数  这里的value接收的就是'success '+Date.now()},reason=>{    console.log(reason);  //onrejected回调函数  这里的reason接收的就是'failed '+Date.now()})

//2. catch只能接收reject的值promise.then(value=>{    console.log(value); }).catch(reason=>{    console.log(reason);})

//3. 也能够只接收成功/失败的值promise.then(value=>{    console.log(value); })promise.then(null,reason=>{   console.log(reason); })复制代码


promise中是先肯定状态仍是先肯定回调?

咱们能够经过定时器的方法人为地改变状态和回调的执行顺序,无论怎样都是能够执行的。可是在程序执行的过程当中,永远都是先确认状态,再执行回调函数的。


JavaScript的执行机制宏任务和微任务 与 Promise

咱们都知道,JavaScript的执行是单线程的,同步任务会率先一件一件得在主线程完成,而异步任务会进入任务队列,等待同步任务完成后执行。

而任务对列中还分为了宏任务和微任务。

宏任务:script,DOM事件函数,ajax,定时器等。

微任务:promise等。

Promise做为典型的微任务,须要注意的是new Promise中的回调函数(也就是执行器函数)是当即执行的,也就是说执行器函数是一个同步回调函数。而promise.then中回调函数才是异步任务(微任务)

还有一点须要注意的是,promise.then中的回调函数必须在promise状态肯定以后才能执行。下面是一个例子:

const promise1 = new Promise(function(resolve, reject) {    console.log(3);    setTimeout(function(){        resolve('Success!');        console.log(1);    },1000)});promise1.then(function(value) {    console.log(value);    console.log(2);});
//代码输出结果:3 (一秒后) 1 success!2
复制代码

代码开始运行后,先从最大的script宏任务开始,new promise直接执行,输出3,setTimeout放入宏任务对列,紧接着的then被放入微任务队列,而本该先执行的微任务,却反而在宏任务结束以后才执行,这里的执行顺序显然是不符合js的执行机制的。

如今,在这段代码里添加一行代码。

const promise1 = new Promise(function(resolve, reject) {    console.log(3);    setTimeout(function(){        resolve('Success!');        console.log(1);    },1000)    resolve('haha');  //我是那行被添加的代码});promise1.then(function(value) {    console.log(value);    console.log(2);});//代码输出结果:3 haha 2 (一秒后)1复制代码

这时,输出的结果就是then在前,setTimeout在后了。这行代码改变的是promise的状态。也就是说,then执行的前提是promise的状态已经被肯定

在没加代码前,虽然在执行机制中then已经能够执行,可是因为promise的状态未肯定,致使then没法执行(then很苦恼,到底应该执行成功的回调仍是失败的回调呢?),没办法,只好等待定时器结束状态肯定下来再执行了。加了这行代码后,状态已经肯定,then天然就能够在setTimeout前执行了。而且因为状态一旦肯定不能更改,因此setTimeout中的resolve('Success!')已经名不副实了。

相关文章
相关标签/搜索