Fork me on GitHub

手动实现一个简单的promise

一直在用promise,也想过自己能不能也实现一个简单的promise,但是一直没有时间;这不最近辞职了,时间就多起来了。当然也参考了网上很多人的实现方法。

本篇文章主要参考自https://github.com/ElemeFE/node-practice/blob/master/control/promise/README.md

promise的意义就是能够很好的控制异步流程,避免回调地狱;首先来看一下promise的基本用法

基本实现效果

1
2
3
4
5
6
7
8
9
10
11
12
let p = new Promisee((resolve, reject) => {
setTimeout(() => {
resolve('hello')
}, 0)
})
p.then((val) => {
console.log(val)
return 'world'
})
.then((val) => {
console.log(val)
})

基本书写

当我们想封装一个函数时,我们只关心两个东西,它需要输入什么以及它要输出什么。

  • 输入一个函数接受两个回调参数
  • 输出一个对象,里面为then函数,函数参数为成功回调和失败回调
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function Promisee(fn) {
    function resolve() {
    }

    function reject() {
    }

    fn(resolve, reject)
    // 返回一个对象
    return {
    then: function(onResolve, onReject) {
    }
    }
    }

加入状态模式

promise内部使用了状态模式,根据不同的状态执行不同的逻辑

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
35
36
37
38
39
40
// 状态唯一
const FULFILLED = Symbol();
const REJECTED = Symbol();
const PEDING = Symbol();

function Promisee(fn) {
// 传入的必须是函数
if (typeof fn !== "function") {
throw new Error('param should be a function!')
}
let state = PEDING
let value = null
function resolve(result) {
// 修改状态
state = FULFILLED
value = result
}

function reject(errror) {
state = REJECTED
value = errror
}

fn(resolve, reject)
// 返回一个对象
return {
then: function(onResolve, onReject) {
switch(state) {
// 成功
case FULFILLED:
onResolve(value)
break
// 失败
case REJECTED:
onReject(value)
break
}
}
}
}

兼容异步

如果代码是异步,根据promise/a+规范,此时状态为peding,所以在peding状态下,我们需要将异步执行的回调函数先存放起来,等到状态变为FULFILLED,或者REJECTED时,再执行。

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 状态唯一
const FULFILLED = Symbol();
const REJECTED = Symbol();
const PEDING = Symbol();

function Promisee(fn) {
// 传入的必须是函数
if (typeof fn !== "function") {
throw new Error('param should be a function!')
}
let state = PEDING
let value = null
let handler = []

function resolve(result) {
// 修改状态
state = FULFILLED
value = result
handler.forEach(next)
handler = null
}

function reject(errror) {
state = REJECTED
value = errror
handler.forEach(next)
handler = null
}

fn(resolve, reject)
// 分离
function next({onResolve, onReject}) {
switch(state) {
// 成功
case FULFILLED:
onResolve && onResolve(value)
break
// 失败
case REJECTED:
onReject && onReject(value)
break
// 异步
case PEDING:
handler.push({ onResolve, onReject })
}
}
// 返回一个对象
return {
then: function(onResolve, onReject) {
next({onResolve, onReject})
}
}
}

then链式调用

then的链式调用需要我们再返回一个promise

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 状态唯一
const FULFILLED = Symbol();
const REJECTED = Symbol();
const PEDING = Symbol();

function Promisee(fn) {
// 传入的必须是函数
if (typeof fn !== "function") {
throw new Error('param should be a function!')
}
let state = PEDING
let value = null
let handler = []

function resolve(result) {
// 修改状态
state = FULFILLED
value = result
handler.forEach(next)
handler = null
}

function reject(errror) {
state = REJECTED
value = errror
handler.forEach(next)
handler = null
}

fn(resolve, reject)
// 分离
function next({onResolve, onReject}) {
switch(state) {
// 成功
case FULFILLED:
onResolve && onResolve(value)
break
// 失败
case REJECTED:
onReject && onReject(value)
break
// 异步
case PEDING:
handler.push({ onResolve, onReject })
}
}
// 返回一个对象
return {
then: function(onResolve, onReject) {
// 链式调用
return new Promisee((resolve, reject) => {
next({
onResolve: (val) => {
// 先调用上一层promise,再调用下一层并且沿用上一层返回的参数
resolve(onResolve(value))
},
onReject: (err) => {
reject(onReject(value))
}
})
})
}
}
}

-------------本文结束感谢您的阅读-------------

本文标题:手动实现一个简单的promise

文章作者:陈晓拉尼

发布时间:2019年01月06日 - 17:01

最后更新:2019年01月11日 - 00:01

原始链接:http://yoursite.com/archives/23803.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。