/** * 浅谈 Promise * 问题:怎么理解的?:Promise是什么,做什么的,有啥问题,有啥解决办法 *//** * 1、Promise是一种异步编程的解决方案,用于解决回调地狱的问题 * 是构造函数,可以理解为是一个容器,里面是异步事件; *//** * 2、 * 特点: * 1、Promise对象的状态不受外界影响,三种状态:pending(初始状态)、fulfilled(成功)、rejected(失败); * 2、状态改变后不再改变,状态不可逆,只能pending到fulfilled,或者pending变成rejected; * 缺点: * 1、无法取消Promise,一旦建立无法取消; * 2、如果不设置回调函数,Promise内容出错,不会反映到外部; * 3、处于pending状态,无法得知是处于了哪一个阶段,是刚开始,还是快结束了; *//** * 3、Promise的方法 && 简单实现 && axios的实现 * Promise.then()、Promise.catch()、Promise.finally() */ // 1、Promise.resolve(value)方法返回一个以给定值解析后的Promise 对象 Promise.resolve('success').then((res) => { console.log(res); // success }, (res) => { // 不会被调用 }) // 2、Promise.reject(reason)方法返回一个带有拒绝原因reason参数的Promise对象 Promise.reject('failed').then((res) => { // 不会被调用 },(res) => { console.log(res); // failed }) // 3、Promise.race(iterable)方法返回一个promise,一旦迭代器中的某个promise解决或者拒绝,返回的promise就会解决或者拒绝 let p1 = new Promise((resolve, reject) => { setTimeout(()=>{resolve('one')}, 1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(()=>{resolve('two')}, 100) }) Promise.race([p1, p2]).then((res) => { console.log(res) }); // two , p2先执行 // 4、Promise.all()方法返回一个Promise实例,接受一个数组(里面都是Promise实例)作为参数,等待所有都成功才会返回成功,或者其中有一个失败则返回失败,且返回该失败的回调; Promise.all = (promise) => { return new Promise((resolve, reject) => { let result = [], index = 0; if(promise.length === 0){ resolve(result); }else{ for (let i = 0; i < promise.length; i++) { Promise.resolve(promise[i]).then((res) => { result[i] = res; // 因为then是异步任务,所以需要另加index if(++index === promise.length) resolve(result); }, error => { reject(error); return; }) } } }) } /** * Promise 实现 Polyfill */ class Rpromise { constructor(excutor) { this.status = 'pending'; // 实例状态 this.fulfilledCallbacks = []; // 成功状态事件池 this.rejectedCallbacks = []; // 失败状态事件池 this.value = undefined; // 记录resolve和reject时候的参数 const resolve = (result) => { // 如果不是pending那么状态已经不能更改了 if(this.status === 'pending'){ this.status = 'resolved'; this.value = result; // 为了避免还没有执行then,成功状态事件池还没有添加这里就同步执行了,因为forEach是同步方法 // 所以需要把循环事件池处理成异步的,考虑到then也是异步的,所以不仅要将这里处理成异步的 // 还要这里的异步在then后执行,then是微任务,加定时器变成宏任务,在then后执行 let time = setTimeout(() => { clearTimeout(time); // 循环执行成功状态事件池中的事件 this.fulfilledCallbacks.forEach(item => item(this.value)); }, 0); } } const reject = (res) => { if(this.status === 'pending'){ this.status = 'rejected'; this.value = res; let time = setTimeout(() => { clearTimeout(time); this.rejectedCallbacks.forEach(item => item(this.value)); }, 0); } } try { excutor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected){ // 需要链式调用then方法,所以then方法的返回值必须是一个promise的实例,而resolve和reject // 两个形参则是用来改变返回的这个promise的状态的,因为下一个then中的回调还挂着返回这个promise // 对象的身上,需要通过控制resolve和reject的执行来控制下一个then中执行的方法 return new Rpromise((resolve, reject) => { if(this.status === 'resolved'){ // 向成功状态事件池添加回调,只添加并没有执行,this指向上一个promise实例, // 什么时候执行?在调用this的resolve方法时被执行,result就是传进来的this.value this.fulfilledCallbacks.push((result) => { // 如果then中的方法执行时报错,直接执行返回的promise的reject方法触发下一个then的失败回调执行 try { let res = onFulfilled(result); if(res instanceof Rpromise){ res.then(resolve, reject); }else{ resolve(res); } } catch (error) { reject(error); } }) } if(this.status === 'rejected'){ this.rejectedCallbacks.push((result) => { try { let res = onRejected(result); if(res instanceof Rpromise){ res.then(resolve, reject); }else{ reject(res) } } catch (error) { reject(error); } }) } }) } } /** * 用Promise实现 axios * 1、创建XMLHttpRequest对象 * 2、使用open函数 * 3、设置onreadystatechange回调 * 4、send请求数据 */ function axios(params) { const {url, method, data} = params; return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onreadystatechange = () => { if(xhr.readyState !== 4) return; if(xhr.statue === 200){ resolve(xhr.response); }else{ reject(xhr.statusText); } } xhr.send(data); }) } /** * 4、Promise的痛点解决 * 1、无法取消Promise, 使用async/await 可以return终止 * 2、不设置回调出错不会反映到外部,使用async/await 可以每个阶段return Promise.reject(new Error('拒绝')) */ // async声明的函数的返回本质上是一个Promise // async是一个关键字,表示异步 function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, "finish"); }); } timeout(2000).then(value => { console.log("第一层" + value); return timeout(2000); }).then(value => { console.log("第二层" + value); return timeout(2000); }).then(value => { console.log("第三层" + value); return timeout(2000); }).then(value => { console.log("第四层" + value); return timeout(2000); }).then(value => { console.log("第五层" + value); return timeout(2000); }).catch(err => { console.log(err); }); // 改用 async async function asyncTimeSys(){ await timeout(1000); console.log("第一层异步结束!") await timeout(1000); console.log("第二层异步结束!") await timeout(1000); console.log("第三层异步结束!") await timeout(1000); console.log("第四层异步结束!") await timeout(1000); console.log("第五层异步结束!") return "all finish"; } asyncTimeSys().then((value)=>{ console.log(value); }); // 误区 :await并不是是把同步变为异步 // async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回, // 等到触发的异步操作完成,再接着执行函数体内后面的语句 async function async1(){ console.log('async1 start') await async2(); console.log('async1 end') } async function async2(){ console.log('async2') } async1(); console.log('i am koala')console.log(timeout()) // async1 start // async2 // i am koala // async1 end // 简单的说,先去执行后面的同步任务代码,执行完成后, // 也就是表达式中的 Promise 解析完成后继续执行 async 函数并返回解决结果
来源:https://www.cnblogs.com/fmixue/p/12013838.html