原⽣JS 实现Promi (详解)
摘要
⾸先呢,Promi是异步中⽐较重要的知识点,学习的最好⽅法就是掌握它的基本原理。
所以这⼀篇主要说⼀下如何⽤JS来实现⼀个⾃⼰的promi。
构造函数
⾸先我们来看⼀下我们是如何使⽤promi的,我们在实例化对象是这么使⽤的:
所以我们在创建我们⾃⼰的类要考虑到如何使⽤这个参数。
西班牙语 我爱你我们来看⼀下, new Promi 的时候传了⼀个回调函数,在这个回调函数中的代码应该是被⽴即执⾏的。
⽽在这个回调函数中,还带有这两个参数resolve和reject(也是回调函数)。
所以在我们的构造函数中,应该是有这两个函数resolve和reject(暂时先不管这两个函数是做什么的)。
我们知道promi是有三个属性的:
pending : 待定 fulfilled : 对应resolve函数 rejected : 对应reject函数
并且状态⼀旦改变就不能再更改了。
所以我们的构造函数之中应该有表⽰当前promi状态的属性。
我们知道不管使⽤resolve还是reject都会传⼊⼀个res变量,作为结果值,所以我们在⽤⼀个属性来保存resolve和reject的结果值。最后我们可以设计出这样的构造函数:
then 和 catch ⽅法
我们先来回顾⼀哈怎么使⽤这两个⽅法: let p1 = new Promi ((resolve , reject ) => { let random = Math .floor (Math .random () * 10); if (random > 4) { resolve ('sucess') } el { reject ('erro') } })
1
2
3
4
5
ladyandgentleman
6
7
8function Mypromi (config ) { this .status = 'pending'; this .res = '' let resolve = (data ) => { this .status = 'fulfilled'; this .res = data } let reject = (data ) => { this .status = 'rejected'; this .res = data } config (resolve , reject )}
1
2
3
4
5
6
7
8
9
10
分享阅读11
12
13
14
上⾯的代码我们可以看到,then和catch⽅法,都接受了⼀个回调函数
⽽这个回调函数的参数也就是我们之前定义的s。
所以我们可以想到这么做:
但是这种⽅法不能实现链式调⽤,就是不能连着使⽤then⽅法。 但是如果我想实现出这个模式,我们应该在then⽅法下回⼀个对象,⽽这个对象正常来讲就是this。 所以我们可以直接返回this吗,看下⾯这个情况。
在then⽅法下如果返回了⼀个新的promi的话,我们就不能直接在then⽅法⾥⾯直接返回this了。
所以我们应该先判断then的回调函数是否返回了新的对象,如果没有才返回当前then的this对象。 p1 .then (res => { console .log (res ); }) .then (res => { console .log (res ); }) .catch (err => { console .log (err ); })
1
2
3
4
5
6
7
8
9
10Mypromi .prototype .then = function (config ) { if (this .status == 'fulfilled') { config (this .res ) }}Mypromi .prototype .catch = function (config ) { if (this .status == 'rejected') { config (this .res ) }}
修改病句类型1
2
3
4
5
6
7
8
910
11p1 .then (res => { console .log (res ); return new Promi ((resolve , reject ) => { resolve ('1111') }) }) .then (res => { console .log (res ); }) .catch (err => { console .log (err ); })
1
2
3
4
5
埃及总统穆巴拉克
6
7
8
9
10
11
12
13Mypromi .prototype .then = function (config ) { if (this .status == 'fulfilled') { var res = config (this .res ) } return res || this ;}Mypromi .prototype .catch = function (config ) { if (this .status == 'rejected') { var res = config (this .res ) } return res || this ;}
1
2
3
4
5
6
7
8
9
10
11
12
13
解决异步问题
上⾯的代码,似乎看着没有什么问题了,但是如果我这么写的话:
问题就⼤⼤的出来了,为什么呢? 因为我在p2.then的时候,定时器没有跑完,所以p2的状态现在还是pending,根本不会⾛下去。这⾥⾯我们⽤⼀种经典的解决模式,在我写之前的axios和路由也经常可以看到。
在then⽅法中,如果当前状态为pending(这句话很重要o),我们就把当前的回调函数保存下来(不⼀定是⼀个,有可能是多个then,所以我们采⽤数组保存)。
那我们保存起来什么时候⽤呢?当然是在定时器结束后⽤!那定时器什么时候结束呢?当然是当前promi状态改变的时候,所以,我们在resolve和reject⽅法之中,要将这些⽅法进⾏调⽤
所以我们要修改构造函数:
然后再修改我们的then和catch⽅法: let p2 = new Mypromi ((resolve , reject ) => { tTimeout (() => { reject ('p2 resolve') }, 1000); })
1
2
3
4
5function Mypromi (config ) { this .status = 'pending'; this .res = ''; this .saveResolve = []; this .saveReject = []; let resolve = (data ) => { if (this .status == 'pending') { this .status = 'fulfilled'; this .res = data this .saveResolve .forEach (val => { val (this .res ) }) } } let reject = (data ) => { if (this .status == 'pending') { this .status = 'rejected'; this .res = data this .saveReject .forEach (val => { val (this .res ) }) } } config (resolve , reject );}
1
2
3
4
5
6
7reception是什么意思
8
9
10
11
12
13
亚洲大学排名
14
15
16
17
18
19
20
21
22
23
24
25
这样关于异步的问题我们就解决了。
all 和race ⽅法
还是⽼样⼦,在写之前我们先回顾⼀下是怎么⽤的:
那我们知道,⼆者都死以⼀个数组作为参数,这⾥⾯我门就不考虑其他的情况了,我就当数组⾥⾯全是promi对象了。。。
⼆者的区别在于:
all:当所有的promi都执⾏完,并且状态都为fulfilled,all⽅法返回的promi为fulfilled,否则为rejected。
race:第⼀个出现结果的promi对象就是race放回的promi的结果。
现在我们来想⼀下all⽅法如何来实现,我们拿到了数组参数之后,⼀定是要遍历⼀遍的。
然后对于每⼀个元素都调⽤then⽅法和catch⽅法。
then⽅法要有⼀个结果数组保存每个promi的结果值。
我们可以⽤⼀个计数器来计算then⽅法的调⽤次数,如果计数器的⼤⼩等于数组长度,那么就证明所有的promi全部都是fulfilled,可以返回结果数组。
catch⽅法只要是被调⽤了⼀次,那么直接返回结果,不多bb,直接返回
最后记住要把新的promi返回o。Mypromi .prototype .then = function (config ) { if (this .status == 'pending') { this .saveResolve .push (config ); } if (this .status == 'fulfilled') { var res = config (this .res ) } return res || this ;}Mypromi .prototype .catch = function (config ) { if (this .status == 'pending') { this .saveReject .push (config ) } if (this .status == 'rejected') { var res = config (this .res ) } return res || this ;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 Mypromi .all ([p2, p3, p4]) .then (res => { console .log (res ); }) .catch (err => { console .log (err ); }) Mypromi .race ([p2, p3, p4]) .then (res => { console .log (res ); }) .catch (err => { console .log (err ); })
1
2
3
fieldofview
4
5
6
7
8
9
10
11
12
13
14
15
race的⽅法的话,实现起来可能就更简单了,不管那个promi的then⽅法还是catch⽅法触发了,直接返回结果:Mypromi .all = function (arr ) { let result = []; let count = 0; let promi = new Mypromi ((resolve , reject ) => { for (var i = 0; i < arr .length ; i ++) { arr [i ] .then (res => { result .push (res ); count ++; if (count == arr .length ) resolve (result ); }) .catch (err => { reject (err ) }) } }) return promi }
1团支书英文
2
3
4
5
6
7
8
9
10
11
12education in china
13
14
15
16
17
18
19Mypromi .race = function (arr ) { let promi = new Mypromi ((resolve , reject ) => { for (var i = 0; i < arr .length ; i ++) { arr [i ] .then (res => { resolve (res ); }) .catch (err => { reject (err ) }) } }) return promi }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15