正在努力加载中...
Promise的相关小结
  1. 1. 前言
  2. 2. 初定义
  3. 3. 方法
  4. 4. Promise.prototype.then()
  5. 5. Promise.prototype.catch()
  6. 6. Promise.all()
  7. 7. Promise.race()
  8. 8. Promise.resolve()
  9. 9. Promise.reject()
  10. 10. 注意点
    1. 10.1. 状态变化
    2. 10.2. 参数/返回值
    3. 10.3. 执行顺序
  11. 11. 手写Promise
  12. 12. 参考文章

前言

网上关于Promise的文章确实是非常多了,但是自己实践的并不多,这里是针对自己的一个知识点小结和梳理,而且由Promise延伸出的关于事件循环的机制也是可以挖出很多东西的,不过这个总结可能就是涉及到一些皮毛,当然啦如果有错误欢迎提出^_^。

初定义

定义:Promise对象用于一个异步操作的最终完成/失败及其结果值的表示。
使用原因:避免回调嵌套层次过多。
拥有状态:

状态转化:

最基本用法:
可以看到创建一个Promise实例,传入的参数是一个函数,这个函数称为executor/执行器。

1
2
3
4
5
6
7
new Promise((resolve, reject) => {
if (success) {
resolve(a) // pending to resolved
} else {
reject(err) // pending to rejectd
}
})

方法

Promise对象本身,有一些方法:

查看Promise的原型,发现它内置有几个方法:

Promise.prototype.then()

1
2
3
promise.then(
() => { console.log('我是成功后被执行的') },
() => { console.log('我是失败后被执行的') })

Promise.prototype.catch()

1
2
3
4
promise.then(
() => { console.log('我是成功后被执行的') }
).catch(
(err) => { console.log(err) })

使用rejects()方法改变状态和抛出错误 throw new Error() 的作用是相同的

Promise.all()

Promise.race()

Promise.resolve()

1
2
3
4
5
6
7
8
Promise.resolve('success')
// 其中[[PromiseStatus]]:"resolved"

Promise.reject('fail')
// 其中[[PromiseStatus]]:"rejected"

Promise.resolve(Promise.reject('fail'))
// 其中[[PromiseStatus]]:"rejected"

由这个例子可以看出浏览器认为resolvedfulfilled是等价的,但Promise.resolve() 不一定让promise最终是fulfilled。所以对于resolved本身和fulfilled的区别,可以理解为resolved等价于compiled,即可能是成功也可能是失败。

Promise.reject()

注意点

状态变化

参数/返回值

1
2
3
4
Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log) //1

因为返回任意一个非Promise 的值都会被包裹成Promise对象,即 return new Error(‘error!!!’)等价于return Promise.resolve(new Error(‘error!!!’))

执行顺序

1
2
3
4
5
6
7
8
9
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)

以下输出:end nextTick then setTimeout1 setTimeout2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
process.nextTick(() => {
console.log('nextTick')
})

setTimeout(() => {
console.log('setTimeout1')
})

Promise.resolve()
.then(() => {
console.log('then')
})

setTimeout(() => {
console.log('setTimeout2')
})

console.log('end')

补充:
macrotasks:

microtasks:

手写Promise

构造函数
首先我们要知道Promise本身拥有的属性:
1.状态(Pending、Fullfied、Rejected),在状态发生改变后,就不会再进行变化了。
2.本次Promise的执行结果,value存储
3.我们最开始传入的方法实际是同步直接执行的。它需要一个resolve方法和reject方法作为参数。
4.如果它返回value还是一个Promise,还是直接返回,执行,直到拿到一个非Promise的结果(借助then)。

这里我们需要保证最后把结果传给then的回调方法们,就需要利用一个setTimeout,把这个传值的环节放在事件循环的最后。
resolvedCallbacks和rejectCallbacks实际存储的都是then调用后拿到的回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
status = STATUS.PENDING
value = undefined
resolvedCallbacks = []
rejectCallbacks = []
resolve = (value) => {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}

// 本轮事件循环的末尾
setTimeout(() => {
if (this.state === STATUS.PENDING) {
this.state = STATUS.FULLFIED;
this.value = value;
this.resolvedCallbacks.forEach(callback => {
callback(value);
})
}
})

this.status = STATUS.FULLFIED
}
reject= (value) => {
this.status = STATUS.REJECT
setTimeout(() => {
if (this.state === PENDING) {
this.state = STATUS.REJECT;
this.value = value;
}
this.rejectCallbacks.forEach(callback => {
callback(value);
});
})
}

then函数
1.then返回的就是一个Promise,入参两个,1个是成功的回调,一个是失败的回调。
2.上面说了,它要把自己的方法放进队列里。我们需要实现一个一个接着去执行,所以需要包裹一层。
如果是同步的方法,我们直接执行完拿到结果就好了,如果是异步的,返回的还是一个Promise.then(Promise)去执行。

参考文章

ES6关于Promise的用法
Promise 必知必会(十道题)
javascript中的异步 macrotask 和 microtask 简介
Tasks, microtasks, queues and schedules
Difference between microtask and macrotask within an event loop context

上一篇 下一篇
ABOUT
欢迎来到小年糕的后花园,年糕的小站开设于2017年,博主年糕君是一个爱好十分广泛的人,也是一个比较佛系的人,不定时爆发脑洞更新(因为是社畜,也可能失踪很久,工作太累了)。 查看更多