class Promise {
queue1 = [] // queue1 为了容纳成功之后的函数们
queue2 = [] // queue2 为了容纳失败之后的函数们
constructor(fn){ // new Promise(fn)
const resolve = (data)=>{ // fn 接受 resolve 并在成功的时候调用
setTimeout(()=>{ // 要等一会,否则 queue1 和 queue2 为空
for(let i =0;i<this.queue1.length;i++){
this.queue1[i](data)
}
})
}
const reject = (reason)=>{
setTimeout(()=>{
for(let i =0;i<this.queue2.length;i++){
this.queue2[i](reason)
}
})
}
fn(resolve, reject)
}
then(s, e){
this.queue1.push(s)
this.queue2.push(e)
return this
}
}
p1 = new Promise((resolve, reject)=>{
console.log('hi2');
if(Math.random()>0.5){
resolve('大')
}else{
reject('小')
}
})
p1.then((data)=>{console.log('成功')}, (reason)=>{console.log('失败')})
首先请先理解上面这段手写的promise,一定要先理解,不然下面的会看不懂
好,我就看到这篇文章的读者理解了,下面看是讲讲我对这个的看法和promise的一些用处
首先:在js文件执行的时候这个class会被初始化,然后到下面的这个new关键字出现,这个时候这个类首先会执行,然后他用的这个then方法也会被定义出来,
之后会执行这个类的constructor函数,在执行的时候,他给传入的这个箭头函数,也就是
(resolve, reject)=>{
console.log('hi2');
if(Math.random()>0.5){
resolve('大')
}else{
reject('小')
}
}
这个函数的两个参数定义成为了两个函数,这个地方,一定一定要看到setTimeout这个定时器,这个是promise的精髓.
为啥说这个setTimeout是精髓,因为他是异步的,开启定时器那么就会放入到异步队列中,下一步就会执行同步代码了,也就是说下文的p1.then()方法将在下一步执行
.then()方法执行的时候,传递了两个参数到queue1 和queue2 这两个队列中
这就好比,我现在准备开始吃饭了,那么下一步是不是需要先准备一个碗盛东西,嘿嘿,那么这个碗就是.then()方法提供的,等同步代码全部执行完毕就开始执行异步队列中的逻辑了
也就是给了你碗了现在可以开吃了,那么就会将这个.then里面传入的回调函数进行执行.
我研究这个主要是在使用nodejs 的时候需要使用sql进行数据处理,然后sql为异步,异步就算了,可这是个使用forEach开启很多个的异步,我想在这个forEach执行完毕之后也就是所有sql执行完毕之后
再进行res.send()操作,显然直接写在sql中是不行了. 然后我看到之前笔记里面的手写promise,得到了新的理解,直接在promise中使用forEach,当然外面需要嵌套tryCatch,因为只要有一个sql出错
那么就需要停止forEach,等到最后执行完毕之后. 嘿嘿,到这里有没有人会想到,这不还是直接开了很多异步,你下面加一个判断每次都会先执行,到了最后一次的时候,没准最后一次的sql还没执行完毕呢!
嘿嘿,这么想是正确的,所以我在最后的判断开了一个宏任务,也就是定时器.这样sql语句的每一次执行都被推送一个异步执行队列中,先进先出.到最后定时器一定会在队列的最后面执行.等执行完毕之后,
就会执行.then()中第一个函数中内容,这样这个需求就被完美满足
最后我想说的是promise不仅是用来解决回掉地狱,我上面说的这种多个异步同时执行,需要在这多个异步都有一个结果之后才能执行的一些逻辑 这样的需求面前,就能使用promise满足需求.
然后promise的原理其实就是: 1.没有.then()方法,那么调用resolve或reject都没啥效果. 2.调用resolve或者reject之前一切都是同步的,调用之后会开启一个异步宏任务,让.then()方法将回调函数
准备好,等所有同步任务执行完毕之后才会执行.then()的回调