Promise从入门到精通
概念
Promise是ES6引入的进行异步编程的新的解决方案
备注:旧计划是单纯的应用回调函数
- 从语法上来说:它就是一个构造函数,
- 从性能上来说:能够封装异步的工作,并且能够对后果进行解决
Promise最大的益处:能够解决回调天堂的问题,并且它在指定回调和错误处理这一块更加的灵便与不便
回调天堂的典型情景:
异步编程有哪些?
答:fs文件操作、数据库操作、AJAX、定时器等等
为什么要应用Promise?
指定回调函数的形式更加灵便
旧的形式:必须在启动异步工作前指定·promise:启动异步工作 => 返回promise对象 => 给promise对象绑定回调函数(甚至能够在异步工作完结后指定多个回调)
反对链式调用,能够解决回调天堂问题
回调天堂的毛病:1)不便于浏览;2)不便于异样解决
Promise的根本流程
promise的状态扭转
状态指的是promise实例中的一个属性:【PromiseState】
pending 未决定的
fulfilled 胜利
rejected 失败
1. pending => fulfilled
2. pending => rejected
promise对象的状态只有这两种扭转,1个promise对象的状态只能扭转一次,
不可能由fulfilled转rejected
也不可能由rejected转fulfilled
promise对象后果值属性介绍
实例对象中另一个属性:【PromiseResult】
保留的是胜利/失败的后果
resolve能够批改PromiseResult的值
rejected能够批改PromiseResult的值
如何应用Promise?
API
1.Promise构造函数:Promise(exector){}
1)exector函数:称为执行器函数 (resolve,reject)=>{}
2)resolve函数:是Promise外部定义的,胜利时咱们调用resolve函数
3)reject函数:是Promise外部定义的,失败时咱们调用reject函数
阐明:exector会在Promise外部立刻同步调用,异步操作在执行器中执行
2.Promise.prototype.then办法:(onResolved,onRejected)=>{}
1)onResolved函数:指定胜利的回调函数 value=>{}
2)onRejected函数:指定失败的回调函数 reason=>{}
阐明:指定用于失去胜利value的胜利回调和用于失去失败reason的失败回调,返回一个新的promise对象
3.Promise.prototype.catch办法:(onRejected)=>{}
onRejected函数:指定失败的回调函数 reason=>{}
阐明:then()的语法糖,相当于then(undefined,onRejected)
4.Promise.resolve办法 (value)=>{}
1)value:胜利的数据或promise对象
阐明:返回一个胜利/失败的promise对象
作用:为了疾速失去一个promise对象,而且可能封装1个值,将这个值转化为promise对象
如果传入的参数为非promise类型的对象,则返回的后果为胜利的promise对象
如果传入的参数为promise对象,则参数的后果决定了resolve的后果
5.Promise.reject办法:(reason)=>{}
作用:疾速返回一个失败的promise对象
返回的后果永远都是失败的promise对象
6.Promise.all办法:(promises数组)=>{}
参数:蕴含n个promise的数组
阐明:返回一个新的promise对象,只有所有的promise都胜利才胜利,只有有一个失败就间接失败
7.Promise.race办法:(promises数组)=>{}
race有赛跑的意思
参数:蕴含n个promise的数组
阐明:返回一个新的promise对象,第一个扭转状态的promise就是最终的后果状态
promise的几个关键问题
1. 如何扭转promise的状态?
(1) resolve(value): 如果以后是pending就会变为fulfilled
(2) reject(reason): 如果以后是pending就会变为rejected
(3) 抛出异样: 如果以后是pending就会变为rejected
2. 一个promise指定多个胜利/失败回调函数, 都会调用吗?
当promise扭转为对应状态时都会调用
3. 扭转promise状态和指定回调函数谁先谁后?
(1) 都有可能, 失常状况下是先指定回调再扭转状态, 但也能够先改状态再指定回调
(2) 如何先改状态再指定回调?
① 在执行器中间接调用resolve()/reject()
② 提早更长时间才调用then()
(3) 什么时候能力失去数据?
① 如果先指定的回调, 那当状态产生扭转时, 回调函数就会调用, 失去数据
② 如果先扭转的状态, 那当指定回调时, 回调函数就会调用, 失去数据
4. promise.then()返回的新promise的后果状态由什么决定?
(1) 简略表白: 由then()指定的回调函数执行的后果决定
(2) 具体表白:
① 如果抛出异样, 新promise变为rejected, reason为抛出的异样
② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
③ 如果返回的是另一个新promise, 此promise的后果就会成为新promise的后果
5. promise如何串连多个操作工作?
(1) promise的then()返回一个新的promise, 能够开成then()的链式调用
(2) 通过then的链式调用串连多个同步/异步工作
let p = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('ok'); },1000);});p.then(v=>{ return new Promise((resolve,reject)=>{ resolve('success'); });}).then(v=>{ console.log(v);}).then(v=>{ console.log(v);})
6. promise异样传透?
(1) 当应用promise的then链式调用时, 能够在最初指定失败的回调,
(2) 后面任何操作出了异样, 都会传到最初失败的回调中解决
let p = new Promise((resolve,reject)=>{ reject('err');});p.then(v=>{ console.log(111);}).then(v=>{ console.log(222);}).then(v=>{ console.log(333);}).catch(r=>{ console.log(r);});
7. 中断promise链?
(1) 当应用promise的then链式调用时, 在两头中断, 不再调用前面的回调函数
(2) 方法: 在回调函数中返回一个pendding状态的promise对象
代码展现
//申明函数 执行器 『同步回调』function Promise(executor) { //设置实例对象的属性 this.PromiseState = 'pending'; this.PromiseResult = undefined; this.callbacks = []; //申明函数 const success = (value) => { if (this.PromiseState !== 'pending') return; //批改状态为胜利 PromiseState this.PromiseState = 'fulfilled'; //设置胜利的后果值 PromiseResult this.PromiseResult = value; //调用回调 if (this.callbacks.length > 0) { this.callbacks.forEach(cbObj => { //执行胜利的回调 cbObj.ok(); }) } } const fail = (reason) => { if (this.PromiseState !== 'pending') return; //批改状态为失败 PromiseState this.PromiseState = 'rejected'; //设置胜利的后果值 PromiseResult this.PromiseResult = reason; //调用回调 if (this.callbacks.length > 0) { this.callbacks.forEach(cbObj => { //执行胜利的回调 cbObj.ng(); }) } } try { //调用执行器函数 executor(success, fail); } catch (e) { //调用 fail 函数 fail(e); }}Promise.prototype.then = function (onFulfilled, onRejected) { //判断 异样穿透 if(typeof onRejected !== 'function'){ onRejected = reason => {throw reason}; } //值传递 if(typeof onFulfilled !== 'function'){ onFulfilled = value => value; } return new Promise((resolve, reject) => { //封装函数简化代码 let callback = (type) => { try { let res = type(this.PromiseResult); //判断 if (res instanceof Promise) { res.then(v => { resolve(v); }, r => { reject(r); }) } else { resolve(res); } } catch (e) { reject(e); } } //判断 胜利 if (this.PromiseState === 'fulfilled') { setTimeout(() => { callback(onFulfilled);// }) } //失败 if (this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected); }) } //pending if (this.PromiseState === 'pending') { //保留回调 this.callbacks.push({ ok: function () { //胜利 callback(onFulfilled); }, ng: function () { callback(onRejected); } }) } });}Promise.prototype.catch = function(onRejected){ return this.then(undefined, onRejected);}Promise.resolve = function(value){ return new Promise((resolve,reject) => { //判断 if(value instanceof Promise){ //value.then(resolve, reject); 这行代码和上面5行代码性能一样 value.then(v=>{ resolve(v); }, r => { reject(r); }); }else{ resolve(value); } })}Promise.reject = function(reason){ return new Promise((resolve, reject) => { reject(reason); })}Promise.all = function (promiseArr) { return new Promise((resolve, reject) => { let count = 0; let arr = []; for (let i = 0; i < promiseArr.length; i++) { promiseArr[i].then(v => { count++; arr[i] = v; if (count === promiseArr.length) { resolve(arr); } }, r => { reject(r); }); } });}Promise.race = function (promiseArr) { return new Promise((resolve, reject) => { promiseArr.forEach(item => { item.then(v => { resolve(v); }, r => { reject(r); }); }); });}
面试题1:
let p = new Promise((resolve, reject) => { reject("error");});p.then(v => { console.log(v);}).then(v => { console.log(v);}, r => { console.log(r); // error}).then(v => { console.log(v); // undefined}, r => { console.warn(r); });