es6-Promise 72行,还有比我少的吗?
如果世界上所有的表白都能成功的话,那这个世界就不会存在像我这样的人了。
晚上我回到宿舍将我要表白她的事告诉了室友,室友纷纷当起了劝退师,觉得我压根配不上她,她有太多优质的选择。陷入爱河的我已经听不进任何人的劝阻了,只要有百分之零点一的机会我就想尝试下。于是接下来的几天我一直在计划我的表白了......
终于等到那天,今天的天气额外的宁静清爽,我以各种借口约她晚上去操场走走,起初她并不愿意,在我的死打烂缠下终于答应了。我提前买好了她喜欢的抹茶味奶茶,少糖。现在仍然记得等待时的心情,激动,紧张,充满期待,没一会,她也下来了,我俩并肩像操场走去,我曾在无数个日夜幻想这个场景。
起先我只是和她聊了下最近的生活,我太紧张了,这是我人生中第一次约女孩出来,也是我即将的第一次表白,我一直不能从话题中找一个契合的时机去表白,走着走着已经围绕操场走了2圈了,她也有点想回去的意思,我突然话锋一转,说最近好多人和你表白呀,里面有你喜欢的吗?她说目前还没有让她心动的,她突然也警觉起来,说了句:该不会你要向我表白吧,我从没考虑过和班上人谈恋爱。我赶紧红着脸回答道:不是的,我也才认识你不久,只是觉得你挺优秀的,想和你交个朋友而已....当时我裂了,铁铁们....
回到宿舍我强装着啥事没发生和他们说道表白延后了,我要充分准备下。半夜我哭了,没有声音,只是觉得心里很难受,甚至自己有点莫名其妙。
第一次表白就这样烂在了我心里,还有那封未送出的信。
........
我如果爱你 绝不学攀援的凌霄花 借你的高枝炫耀自己
我如果爱你 绝不学痴情的鸟儿 为绿荫重复单调的歌曲
........
Promise用法及手写一个Promise
Promise 简介和基本用法
promise 是一个拥有 then
方法的对象或函数,其行为符合本规范;
promise A+规范我不会详细介绍,感兴趣的可以去promise官网了解。
then
方法接受两个参数 onFulfilled, onRejected
。前者是成功的回调,后者是失败的回调。如果Promise里面执行的是resolve进入onFulfilled
,执行reject进入onRejected
。
人狠话不多,直接上干货了。
new Promise((reslove, reject) => { console.log(1111); setTimeout(() => { console.log('setTimeut', 2222); reslove(1); }, 1000); }).then( (res) => { console.log(3333); }, (err) => console.log(err), ); 复制代码
上图代码的执行结果如下:
Promise.all
使用场景:一次请求多个接口,需要同时拿到里面的信息。
接下来用promise结合setTimeout模拟axios
var promise1 = Promise.resolve('我'); var promise2 = new Promise(function(resolve, reject) { setTimeout(resolve, 1000, '不是'); }); var promise3 = new Promise(function(resolve, reject) { setTimeout(resolve, 2000, '舔狗'); }); Promise.all([promise1, promise2, promise3]).then(function(values) { console.log(values); }); 复制代码
下图是values的打印结果
Promise.all 弊端
但Promise.all是有弊端的,假如你一次请求5个接口,只要有一个接口请求失败,他将会走到catch
var promise1 = Promise.resolve('我'); var promise2 = new Promise(function (resolve, reject) { setTimeout(reject, 1000, '不是'); }); var promise3 = new Promise(function (resolve, reject) { setTimeout(resolve, 2000, '舔狗'); }); Promise.all([promise1, promise2, promise3]) .then(function (values) { console.log(values); }) .catch((err) => console.log(err)); 复制代码
上面我把promise2 里面换成了reject,它走到catch,下图是打印的err
es11 的 Promise.allSettled 解决了Promise.all弊端
var promise1 = Promise.resolve('我'); var promise2 = new Promise(function (resolve, reject) { setTimeout(reject, 1000, '不是'); }); var promise3 = new Promise(function (resolve, reject) { setTimeout(resolve, 2000, '舔狗'); }); Promise.allSettled([promise1, promise2, promise3]) .then(function (values) { console.log(values); }) .catch((err) => console.log(err)); 复制代码
无论是有失败的请求,他都会走到then里面,并用对象将结果包起来,下图是打印的values
Promise.race
多个请求中,那个先执行就返回该请求的结果,慢的就忽视了
var promise2 = new Promise(function (resolve, reject) { setTimeout(resolve, 1000, '班花'); }); var promise3 = new Promise(function (resolve, reject) { setTimeout(resolve, 2000, '舔狗'); }); Promise.all([ promise2, promise3]) .then(function (values) { console.log(values); }) 复制代码
values的打印结果如下
Promise 值穿透 及如何中断Promise 链式请求
穿透
Promise.resolve(1) .then(2) // 注意这里 .then(Promise.resolve(3)) .then(console.log); // 输出1 这一步等同 .then((res)=>{console.log(res)}) 复制代码
return 一个值修改下一个then里面的value
Promise.resolve(1) .then(function(){return 2}) .then(Promise.resolve(3)) .then(console.log) // 输出2 复制代码
Promise.resolve(1) .then(function(){return 2}) .then(function(){return Promise.resolve(3)}) .then(console.log) // 输出3 复制代码
如何中断Promise
中断Promise只有一种方法,那就是让他的状态变为pending
Promise是有三种状态 pending
,fulfilled
,or rejected
const promise = new Promise((resolve, reject) => { resolve(111); }).then((res)=>{ console.log(res) //打印111 return 2222 }).then(res=>{ console.log(res) //打印222 return new Promise(()=>{}) }).then(res=>{ console.log(3333) //不会打印,被中断了 }) 复制代码
手写Promise
下图是我们常见的业务场景,由浅入深,我们先单纯的实现下面这个例子
new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log(1) resolve(2) },1000) }).then(res=>{ console.log(res) }) 复制代码
是不是很简单,x instanceof myPromise ? x.then(resolve, reject) : resolve(x);
就这行需要细品一下,如果卡在了setTimeout,可以看看事件循环机制,如果不懂class的可以看看我的第一文章
// const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; class myPromise { constructor(executor) { let self = this; self.status = PENDING; self.value = undefined; self.reason = undefined; self.onResolvedCallbacks = []; self.onRejectedCallbacks = []; let resolve = (value) => { if (self.status === PENDING) { self.status = FULFILLED; self.value = value; self.onResolvedCallbacks.forEach((fn) => fn()); } }; executor(resolve); } then(onFulfilled, onRejected) { let self=this return new myPromise((resolve, reject) => { if (self.status === 'pending') { self.onResolvedCallbacks.push(() => { let x = onFulfilled(self.value); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); }); self.onRejectedCallbacks.push(() => { let x = onRejected(self.reason); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); }); } }); } } 复制代码
下图我加入了reject,也完善了then方法里面当状态位fulfilled和rejected。代码量其实并不多....
const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; class myPromise { constructor(executor) { let self = this; self.status = PENDING; self.value = undefined; self.reason = undefined; self.onResolvedCallbacks = []; self.onRejectedCallbacks = []; let resolve = (value) => { if (self.status === PENDING) { self.status = FULFILLED; self.value = value; self.onResolvedCallbacks.forEach((fn) => fn()); } }; let reject = (reason) => { if (self.status === PENDING) { self.status = REJECTED; self.reason = reason; self.onRejectedCallbacks.forEach((fn) => fn()); } }; try { executor(resolve, reject); } catch { reject(err); } } then(onFulfilled, onRejected) { //处理then里面不是回调函数情况 //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v; onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err; }; let self = this; return new myPromise((resolve, reject) => { if (self.status === 'fulfilled') { setTimeout(() => { try { let x = onFulfilled(self.value); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); } catch (err) { reject(err); } }, 0); } if (self.status === 'rejected') { setTimeout(() => { try { let x = onRejected(self.reason); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); } catch (err) { reject(err); } }, 0); } if (self.status === 'pending') { self.onResolvedCallbacks.push(() => { setTimeout(() => { let x = onFulfilled(self.value); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); }, 0); }); self.onRejectedCallbacks.push(() => { setTimeout(() => { let x = onRejected(self.reason); x instanceof myPromise ? x.then(resolve, reject) : resolve(x); }, 0); }); } }); } } 复制代码
仔细分析下onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
和 let x = onFulfilled(self.value);
,你就知道下图为啥是这个结果了
Promise.resolve
太简单了吧
static resolve(data){ return new Promise((resolve,reject)=>{ resolve(data); }) } 复制代码
Promise.all
promise.race我就不写了,大家可以参考all想想如何实现
static all(values) { if (!Array.isArray(values)) { return new TypeError("请输入一个数组") } return new Promise((resolve, reject) => { let resultArr = []; let len = 0; const dealFn = (value, index) => { resultArr[index] = value; if (++len === values.length) { resolve(resultArr) } } for (let i = 0; i < values.length; i++) { let value = values[i]; //判断value是否还是个promise if (value && typeof value.then === 'function') { value.then((value) => { dealFn(value, i); }, reject); } else { dealFn(value, i); } } }); } 复制代码
总结
我用setTimeout模拟去实现它的延迟执行,没有过多的处理promise整体的容错性,真实的源码用了大量的回调去处理异步执行问题,我只是实现了Promise的回调思想。如果想深入学习Promise的可以去看看官网,我已经晕倒在里面了。只要你认真读懂以上内容,至少不会担心面试官问你promise了
作者:舔狗的泪
链接:https://juejin.cn/post/7026896760152784910