标签:结果 用户 for 理解 typeof html fun pen cal
let p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.log(‘执行完成Promise‘); resolve(‘要返回的数据可以任何数据 例如接口返回数据‘); }, 2000); }); console.log(‘中间‘); p.then(res => { console.log(‘then成功的回调是:‘, res) }) console.log(‘结尾‘)
上面的例子说明了promise可以很好的处理异步操作。因为promise的then方法,是在 resolve函数执行之后才调用的。
首先理解一下promise
很烦。
apiA({
handeleSucess(resA){
apiB({
handleSucess(resB){
apiC({
handleSucess(resc)
})
}
})
}})
简单的实现promise
const PENDING = ‘PENDING‘; const RESOLVED = ‘RESOLVED‘; const REJECTED = ‘REJECTED‘; class PromiseA { constructor(executor) { this.status = PENDING; // 宏变量, 默认是等待态 this.value = undefined; // then方法要访问到所以放到this上 this.reason = undefined; // then方法要访问到所以放到this上
this.onResolvedCallbacks = [];// 专门存放成功的回调函数 this.onRejectedCallbacks = [];// 专门存放成功的回调函数
let resolve = (value) => { if (this.status === PENDING) {// 保证只有状态是等待态的时候才能更改状态 this.value = value; this.status = RESOLVED; // 监听回调函数,需要让成功的方法依次执行 this.onResolvedCallbacks.forEach(fn => fn()); } }; let reject = (reason) => { if (this.status === PENDING) { this.reason = reason; this.status = REJECTED; // 需要让失败的方法依次执行 this.onRejectedCallbacks.forEach(fn => fn()); } }; // 执行executor传入我们定义的成功和失败函数:把内部的resolve和reject传入executor中用户写的resolve, reject try { executor(resolve, reject); } catch(e) { console.log(‘catch错误‘, e); reject(e); //如果内部出错 直接将error手动调用reject向下传递 } } then(onfulfilled, onrejected) {
if (this.status === RESOLVED) { onfulfilled(this.value); } if (this.status === REJECTED) { onrejected(this.reason); } // 处理异步的情况,pending的时候,把任务加入callback队列 if (this.status === PENDING) { // this.onResolvedCallbacks.push(onfulfilled); 这种写法可以换成下面的写法,多包了一层,这叫面向切片编程,可以加上自己的逻辑 this.onResolvedCallbacks.push(() => { // TODO ... 自己的逻辑 onfulfilled(this.value); }); this.onRejectedCallbacks.push(() => { // TODO ... 自己的逻辑 onrejected(this.reason); }); } } }
调用:
let promise = new PromiseA((resolve, reject) => { setTimeout(() => { resolve(‘xxx‘); }, 1000); }); // 发布订阅模式应对异步 支持一个promise可以then多次 promise.then((res) => { console.log(‘成功的结果1‘, res); }, (error) => { console.log(error); }); promise.then((res) => { console.log(‘成功的结果2‘, res); }, (error) => { console.log(error); });
class PromiseA { constructor(executor) { this.status = PENDING; // 宏变量, 默认是等待态 this.value = undefined; // then方法要访问到所以放到this上 this.reason = undefined; // then方法要访问到所以放到this上 // 专门存放成功的回调函数 this.onResolvedCallbacks = []; // 专门存放成功的回调函数 this.onRejectedCallbacks = []; let resolve = (value) => { if (this.status === PENDING) { // 保证只有状态是等待态的时候才能更改状态 this.value = value; this.status = RESOLVED; // 需要让成功的方法一次执行 this.onResolvedCallbacks.forEach(fn => fn()); } }; let reject = (reason) => { if (this.status === PENDING) { this.reason = reason; this.status = REJECTED; // 需要让失败的方法一次执行 this.onRejectedCallbacks.forEach(fn => fn()); } }; // 执行executor 传入成功和失败:把内部的resolve和 reject传入executor中用户写的resolve, reject try { executor(resolve, reject); // 立即执行 } catch (e) { console.log(‘catch错误‘, e); reject(e); //如果内部出错 直接将error 手动调用reject向下传递 } } then(onfulfilled, onrejected) {
// 为了实现链式调用,创建一个新的promise let promise2 = new Promise((resolve, reject) => { if (this.status === RESOLVED) { // 执行then中的方法 可能返回的是一个普通值,也可能是一个promise,如果是promise的话,需要让这个promise执行 // 使用宏任务把代码放在一下次执行,这样就可以取到promise2,为什么要取到promise2? 这里在之后会介绍到 setTimeout(() => { try {
let x = onfulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { // 一旦执行then方法报错就走到下一个then的失败方法中 console.log(e); reject(e); } }, 0); } if (this.status === REJECTED) { setTimeout(() => { try { let x = onrejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); } // 处理异步的情况 if (this.status === PENDING) { // 这时候executor肯定是有异步逻辑 this.onResolvedCallbacks.push(() => { setTimeout(() => { try { let x = onfulfilled(this.value); // 注意这里传入的是promise2的resolve和reject resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { let x = onrejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); } }); return promise2; } }
setTimeout
?:因为Promise本身是处理一个异步方法,必须得在执行栈执行完了在去取他的值,所以,所有的返回值都得包一层异步setTimeout。resolvePromise
是什么?因为then返回的是promise对象的,如果是promise对象,需要将他拆解,直到不是promise对象,取出其中的值。
resolvePromise函数,用来规程化的,用来处理then内部回调函数是promise函数的,
function resolvePromise(promise2, x, resolve, reject) { if((typeof x === ‘object‘ && x != null) || typeof x === ‘function‘) { // 有可能是promise, 如果是promise那就要有then方法 let then = x.then; if (typeof then === ‘function‘) { // 到了这里就只能认为他是promise了 // 如果x是一个promise那么在new的时候executor就立即执行了,就会执行他的resolve,那么数据就会传递到他的then中 then.call(x, y => {// 当前promise解析出来的结果可能还是一个promise, 直到解析到他是一个普通值 resolvePromise(promise2, y, resolve, reject);// resolve, reject都是promise2的 }, r => { reject(r); }); } else { // 出现像这种结果 {a: 1, then: 1} resolve(x); } } else { resolve(x); } }
catch方法其实就是没有成功回调的then方法,
//异常处理 用于指定发生错误时的回调函数。 //promise抛出一个错误,就被catch()方法指定的回调函数捕获 Promise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) }
/** * finally 函数 promise m每次执行后都会进行执行 * @param {*} cb */ PromiseA.prototype.finally = function (cb) { //finally 传入函数,无论成功或者失败都会执行 return this.then(data => { //Promise.resolve 可以等待这个promise完成 return Promise.resolve(cb().then(() => data)) }, err => { //失败的时候也执行 return Promise.reject(cb().then(() => { throw err })) }) }
Promise.all可用于接收一个数组作为参数,参数可以不是数组,但是必须有Iterator接口,且返回的每个成员都是Promise的实例,他的结果是根据传入的数据进行变化的
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回),所有的成功才会成功,一个失败就会失败 Promise.all = function(promiseList){ let arr = [] let i = 0 function processData(index,data){ arr[index] = data i++ if(i == promises.length){ resolve(arr) } } return new Promise((resolve,reject)=>{ for(let i=0;i<promises.length;i++){ promises[i].then(data=>{ processData(i,data) },reject) } }) }
其原理就是将参数中的数组取出遍历,每当执行成功都会执行
processData
方法,processData
方法就是用来记录每个Promise的值和它对应的下标,当执行的次数等于数组长度时就会执行resolve,把arr的值给then。这里会有一个坑,如果你是通过arr数组的长度来判断他是否应该resolve的话就会出错,为什么呢?因为js数组的特性,导致如果先出来的是1位置上的值进arr,那么0位置上也会多一个空的值,所以不合理。
//race方法 Promise.race = function(promises){ return new Promise((resolve,reject)=>{ for(let i=0;i<promises.length;i++){ promises[i].then(resolve,reject) } }) }
标签:结果 用户 for 理解 typeof html fun pen cal
原文地址:https://www.cnblogs.com/jwenming/p/14481446.html