Promise是ES6提供的一种解决异步编程的方案。web
Promise的本质是一个构造函数,咱们能够使用new Promise来建立Promise实例对象,利用Promise对象的方法进行异步编程。ajax
1. Promise定义回调函数的方式更灵活。sql
使用纯回调函数解决异步问题,回调函数必须在一开始就被指定,而Promise的回调函数能够在启动了异步任务后指定,甚至能够在异步任务结束后指定。编程
2. Promise能够解决回调函数由于嵌套形成的回调地狱。promise
若是后面的异步操做,须要拿到前面异步操做的数据后才能执行,使用纯回调函数,会出现层层嵌套的问题。形成的结果是代码不易阅读,不易维护。bash
Promise的三种状态——pending、resolved、rejectedkoa
新建一个Promise对象时,初始的状态为pending(等待中),调用resolve(),状态变为resolved/fullfilled(成功)。调用reject(),状态变为rejected(失败)。ssh
状态一旦改变,就没法再改变。也就是说,若是已经调用了resolve()和reject()中任意一个函数,再进行调用,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的执行是单线程的,同步任务会率先一件一件得在主线程完成,而异步任务会进入任务队列,等待同步任务完成后执行。
而任务对列中还分为了宏任务和微任务。
宏任务: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!')已经名不副实了。