主要为了解决回调地狱的问题html
异步结构不清晰,promise可让异步操做结构变得很清晰面试
executor是带有 resolve
和 reject
两个参数的函数 。Promise构造函数执行时当即调用executor
函数, resolve
和 reject
两个函数做为参数传递给executor
(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve
和 reject
函数被调用时,分别将promise的状态改成fulfilled(完成)或rejected(失败)。executor 内部一般会执行一些异步操做,一旦异步操做执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改为fulfilled,要么调用reject
函数将promise的状态改成rejected。若是在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。ajax
简单理解上面一段话,new Promise()里面接收一个函数,这个函数会理解执行,函数里面有两个参数resolve和reject,函数的执行体里面是异步的操做,异步操做有成功有失败数组
resolve
去接收成功的值reject
去接收失败的值new Promise( function(resolve, reject) {...} /* executor */ );
简单例子promise
let p1=new Promise(function(resolve,reject){ setTimeout(function(){ let num=new Date().getTime(); num%2==0?resolve('成功'):resolve('失败') },0) }) p1.then(function(value){ console.log(value) },function(reason){ console.log(reason) })
连写异步
let p1=new Promise(function(resolve,reject){ setTimeout(function(){ let num=new Date().getTime(); num%2==0?resolve('成功'):resolve('失败') },0) }).then(function(value){ console.log(value) },function(reason){ console.log(reason) })
若是一个promise即调用了resolve,又调用了reject,谁先调用,最后就走对应的方法,async
new Promise(function (resolve, reject) { resolve("成功") reject("失败") console.log("执行了") }).then(value => { console.log(value) }, reason => { console.log(reason) }) // 执行了 // 成功
若是没有成功,刚在then的第二个参数写的失败的回调函数,其实也能够用catchide
new Promise(function (resolve, reject) { reject("失败") resolve("成功") }) .then(value => { console.log(value) }) .catch(reason => { console.log(reason) }) // 失败
成功的语法糖函数
let p1=new Promise(function(resolve,reject){ resolve(11) }) p1.then(function(value){ console.log(value) })
Promise.resolve()ui
const p1=Promise.resolve(11); //跟上面是同样的 p2.then(value=>{console.log(value)})
失败的语法糖
const p3=Promise.reject(33) p2.then(null,reason=>{console.log(reason)})
Promise.All():发送了多个请求,只有所有成功才走成功的处理,只要其中有一个失败就失败,这个返回的是p2的缘由
const p1 = Promise.resolve(11); //跟上面是同样的 const p2 = Promise.reject(22) const p3 = Promise.reject(33) const pAll = Promise.all([p1, p2, p3]) pAll.then( value => {}, reason => { console.log(reason) } )
const p1 = Promise.resolve(11); //跟上面是同样的 const p2 = Promise.resolve(22) const p3 = Promise.resolve(33) const pAll = Promise.all([p1, p2, p3]) pAll.then( values => { console.log(values) } ) //[11,22,33]
多个异步任务,谁先执行完就用谁的,能够用setTimeout延迟去模拟,这里我就不试了
const p1 = Promise.resolve(11); //跟上面是同样的 const p2 = Promise.resolve(22) const p3 = Promise.resolve(33) const pRace = Promise.race([p1, p2, p3]) pRace.then( value => { console.log(value) } )
若是第一个执行完是一个失败的,那就走失败
const p1 = Promise.reject(11); //跟上面是同样的 const p2 = Promise.resolve(22) const p3 = Promise.resolve(33) const pRace = Promise.race([ p1,p2, p3]) pRace.then( value => { console.log(value) }, reason=>{ console.log(reason) } )
resolve(value): 若是当前是pendding就会变为resolved reject(reason): 若是当前是pendding就会变为rejected 抛出异常: 若是当前是pendding就会变为rejected
//若是当前是pendding就会变为rejected,内部抛出也是这样 const p=new Promise((resolve,reject)=>{ throw new Error('出错了') }) const p = new Promise((resolve, reject) =>{ //resolve(1)//promies变为resolved成功状态 //reject(2)//promise变为rejected失败状态 //throw new Error("出错了")//抛出异常promise变为rejected失败状态,reason 为抛出的error throw 3 }); p.then( reason => {console.log("reason:", reason)}//3 )
都会调用
const p1=Promise.resolve('11') p1.then(value=>{ console.log("第一次"+value) }) p1.then(value=>{ console.log("第二次"+value) }) //第一次11 //第二次11
3.一、都有可能,正常状况下时先指定回调函数再改变状态,但也能够先改变状态再指定回调函数 3.二、如何先改变状态再指定回调? 3.2.一、在执行器中直接调用resolve()/reject() 3.2.二、延迟更长时间才调用then()
new Promise((resolve, reject) =>{ setTimeout(()=>{ resolve(1)//后改变的状态(同时指定数据),异步执行回调函数 }, 1000) }).then(//先指定回调函数,保存当前指定的回调函数 value => {console.log("value1:", value)}//value1: 1 )
若是没有返回值也没有抛出错误,就走成功undefined
4.一、简单表达:由then()指定的回调函数执行的结果决定 4.二、详细表达: 4.2.一、若是抛出异常,新promise变为rejected,reason为抛出的异常 4.2.二、若是返回的是非promise的任意值,新的promise变为resolved,value为返回的值 4.2.三、若是返回的是另外一个新promise,此promise的结果就会成为新promise的结果
new Promise((resolve,reject)=>{ setTimeout(function(){ resolve(11) },1000) }) .then(value=>{ console.log("第一次"+value) }) .then(value=>{ console.log("第二次"+value) }) //第一次11 //第二次undefined
new Promise((resolve,reject)=>{ setTimeout(function(){ reject(11) },1000) }) .then(value=>{ console.log("成功第一次"+value) },reason=>{ console.log("失败第一次"+reason) }) .then(value=>{ console.log("成功第二次"+value) },reason=>{ console.log("失败第二次"+reason) }) //失败第一次11 // 成功第二次undefined
如下都是针对第二次then的结果
new Promise((resolve,reject)=>{ setTimeout(function(){ resolve(11) },1000) }) .then(value=>{ console.log("成功第一次"+value) // return 2 //成功第二次2 // return Promise.resolve(2) //成功第二次2 // return Promise.reject(2) //失败第二次2 throw 3; //失败第二次3 },reason=>{ console.log("失败第一次"+reason) }) .then(value=>{ console.log("成功第二次"+value) },reason=>{ console.log("失败第二次"+reason) })
一、promise的then()返回一个新的promise,能够当作then()的链式调用 二、经过then的链式调用串连多个同步/异步任务
new Promise((resolve, reject) =>{ setTimeout(()=>{ console.log("执行任务1(异步)") resolve(1) },1000); }).then( value => { console.log("任务1的结果:", value) console.log("执行任务2(同步):") return 2 } ).then( value => { console.log("任务2的结果():", value) return new Promise((resolve, reject)=>{ setTimeout(()=>{ console.log("执行任务3(异步)") resolve(3) },1000) }) } ).then( value => { console.log("任务3的结果", value) } ) /* 执行任务1(异步) 任务1的结果: 1 执行任务2(同步): 任务2的结果(): 2 执行任务3(异步) 任务3的结果 3 */
一、当使用promise的then链式调用时,能够在最后指定失败的回调 二、前面任何操做出了异常,都会传到最后失败的回调中处理
第一个走的失败的回调,可是失败的回调没有写,默认他会执行 reason=>{throw reason},到第三个时,因为第二个没有抛出异常,也没有返回值,因此走成功值为undefined
catch在后面也不会成功,由于第三个走的成功,因此不会执行catch
new Promise((resolve, reject) => { reject(1) }).then( value => { console.log("onResolveed1():", value) return Promise.reject(2) } ).then( value => { console.log("onResolveed2():", value) return 3 }, reason => { console.log("第二个失败"+reason) } ).then( value => { console.log("onResolveed3()", value) } ).catch(err=>{ console.log("catch"+err) }) /* 第二个失败1 onResolveed3() undefined */
默认在catch后面的then函数,执行成功和失败回调和上面的规则是同样的
new Promise((resolve, reject) => { reject(1) }).catch(err => { console.log(err) }).then(value => { console.log("成功"+value) }, reason => { console.log("失败"+reason) }) /* 1 成功undefined */
若是我不想执行后面then的函数呢?这就看下一个中断promise链
一、当时用promise的then的链式调用时,在中间中断,再也不调用后面的回调函数 二、办法:在回调函数中返回一个pedding状态的promise对象
new Promise((resolve, reject) => { reject(1) }).catch(err => { console.log(err) return new Promise((resolve,rejuct)=>{}) //返回一个pending的promise }).then(value => { console.log("成功"+value) }, reason => { console.log("失败"+reason) })
一、函数的返回值为promise对象 二、promise对象的结果由async函数执行的返回值决定
只要加了async,返回一个promise,里面保存了状态,若是async函数成功,下面就走成功回调,若是是失败,就失败的回调函数函数
async function fn1() { return 1 } let result=fn1(); console.log(result) //Promise
async function fn1() { return 1 } fn1().then(value=>{ console.log(value) }) //1
该指令会暂停异步函数的执行,并等待Promise执行,而后继续执行异步函数,并返回结果。
一、await右侧的表达式通常为promise对象,但也能够是其余的值 二、若是表达式是promise对象,await返回的是promise成功的值 三、若是表达式是其余值,直接将此值做为await的返回值
若是value的右边是promise,返回的是promise成功时候的值
若是value的右边是promise,返回的是promise失败时候的值,就用try catch来获取
若是value右边的不是promise,返回的是值自己
function fn2() { return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(5) },10) }) } async function fn1() { const value=await fn2(); console.log(value) } fn1() //5
注意:
await必须写在async函数中,可是async函数中能够没有await
若是await的promise失败了,就会抛出异常,须要经过try...catch来捕获处理
一、JS中用来存储执行回调函数的队列包含2个不一样特定的队列 二、宏队列:用来保存带执行的宏任务,好比:定时器回调,DOM事件回调,ajax回调 三、微队列:用来保存待执行的微任务,好比:promise的回调,MutationObserver的回调 四、JS执行时会区别这2两个队列 一、JS引擎首先必须先执行全部的初始化同步任务代码 二、每次准备取出第一个宏任务前,都要将全部的微任务一个一个取出来执行
注意promise放在微任务里面,须要更改状态才会放到微任务里面,好比是从pending =》resolved
或者 pedding变为rejected 才会放到微队列
setTimeout(()=>{ console.log('settimeout') },0) Promise.resolve(1).then(value=>{ console.log("promise"+value) }) /* promise1 settimeout */
js会把程序走一遍,定时器加到宏队列,promise加到微队列,
每次会先把微队列执行完在执行宏队列
setTimeout(()=>{ console.log('定时器1') },0) setTimeout(()=>{ console.log('定时器2') },0) Promise.resolve(1).then(value=>{ console.log("第一个promise"+value) }) Promise.resolve(2).then(value=>{ console.log("第二个promise"+value) }) /* 第一个promise1 第二个promise2 定时器1 定时器2 */
这里看下是先执行 第三个promise 仍是先执行 定时器2
setTimeout(()=>{ console.log('定时器1') Promise.resolve(3).then(value=>{ console.log("第三个promise"+value) }) },0) setTimeout(()=>{ console.log('定时器2') },0) Promise.resolve(1).then(value=>{ console.log("第一个promise"+value) }) Promise.resolve(2).then(value=>{ console.log("第二个promise"+value) }) /* 第一个promise1 第二个promise2 定时器1 第三个promise3 定时器2 */
这个也很好理解,当执行第一个定时器时,就把promise添加到了微队列
执行定时器2的时候,这个时候把微队列的取出来执行,因此第三个promise 先执行 定时器2后执行
setTimeout(()=>{ console.log(1) },0) new Promise((resolve)=>{ console.log(2) resolve() }).then(()=>{ console.log(3) }).then(()=>{ console.log(4) }) console.log(5) //25341
第一个看同步执行 25
当执行到第一个then时,上面已经有结果了 pedding变为resolved ,因此放到了微队列了
这时候执行第一个then,执行完了第二个then就有状态变化了 pedding变为resolved,这里也放到了微队列
最后执行定时器
const first = () => (new Promise((resolve, reject) => { console.log(3); let p = new Promise((resolve, reject) => { console.log(7); setTimeout(() => { console.log(5); resolve(6) }, 0) resolve(1) }) resolve(2) p.then((arg) => { console.log(arg) }) })) first().then((arg) => { console.log(arg); }); console.log(4); //374125
第一步同步执行:执行第一个promise输出3,接着执行第二个promise里面接着输出7,
setTimeout(() => { console.log(5); resolve(6) }, 0)
定时器放在宏队列
往下执行
p.then((arg) => { console.log(arg) }) //这个上面执行 resolve(1)的时候就有结果了,arg的值为1,有未成功-》成功的状态变化,因此这个加入到微队列里面[then2]
resolve(2) //这句话表明了第一个promise的状态右不成功到成功 first().then((arg) => { console.log(arg); }); //这个第一个promise的then方法的回调函数也放在队列里,如今队里 [then2(1),then2(2)]
如今执行console.log(4) ,目前执行第一遍输出的是 3,7,4
如今取出微队列 输出 1,2
最后执行定时器 输出5,那个定时器的resolve(6)没有任何意义,由于改变了一次就不能在改变状态了
因此随后输出的是3,7,4,1,2,5
记住一句话:状态只能改变一次,因此就resolve('success1');是有效的
const promise = new Promise((resolve, reject) => { resolve('success1'); reject('error'); resolve('success2'); }); promise.then((res) => { console.log('then:', res); }).catch((err) => { console.log('catch:', err); }) //then: success1
resolve 函数将 Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操做成功时调用,并将异步操做的结果,做为参数传递出去; reject 函数将 Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操做失败时调用,并将异步操做报出的错误,做为参数传递出去。 而一旦状态改变,就不会再变。 因此 代码中的reject('error'); 不会有做用。 Promise 只能 resolve 一次,剩下的调用都会被忽略。 因此 第二次的 resolve('success2'); 也不会有做用。