├── README.md
├── .gitignore
├── .idea
└── vcs.xml
├── package.json
├── test
└── index.js
├── prototype
├── promise_async_2.js
├── promise_1.js
├── promise_withCatchError_4.js
├── promise_chain_3.js
├── promise_transmit_value_5.js
├── promise_async_then_6.js
├── promise_nextTick_7.js
├── promise_without_called_8.js
├── promise_with_called_9.js
└── promise_final_10.js
├── testPromise.js
├── lib
└── promise.js
├── How to implement a Promise.md
└── How to implement a Promise_copy.md
/README.md:
--------------------------------------------------------------------------------
1 | # JSPI
2 | Just a simple Promise/A+ implementation
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | /node_modules
3 | /.happypack
4 | .idea
5 | *.log
6 | npm-debug.log
7 | npm-debug.log*
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jspi",
3 | "version": "1.0.0",
4 | "description": "Just a simple Promise/A+ implementation",
5 | "main": "lib/promise",
6 | "scripts": {
7 | "test": "mocha"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/yonglijia/JSPI.git"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "bugs": {
16 | "url": "https://github.com/yonglijia/JSPI/issues"
17 | },
18 | "homepage": "https://github.com/yonglijia/JSPI#readme",
19 | "devDependencies": {
20 | "promises-aplus-tests": "^2.1.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var Promise = require('../lib/promise');
2 | var promisesAplusTests = require("promises-aplus-tests");
3 |
4 | var adapter = {
5 | resolved: Promise.resolve,
6 | rejected: Promise.reject,
7 | deferred: function () {
8 | var resolve, reject;
9 | var promise = new Promise(function () {
10 | resolve = arguments[0];
11 | reject = arguments[1];
12 | });
13 | return {
14 | promise: promise,
15 | resolve: resolve,
16 | reject: reject
17 | };
18 | }
19 | };
20 |
21 | describe("Promises/A+ Tests", function () {
22 | promisesAplusTests.mocha(adapter);
23 | });
--------------------------------------------------------------------------------
/prototype/promise_async_2.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 |
3 | let _this = this
4 | _this.status = 'pending'
5 | _this.value = null
6 | _this.reason = null
7 |
8 | //-----------add--------------
9 | _this.onFulfilledCallbacks=[]
10 | _this.onRejectedCallbacks=[]
11 |
12 | function resolve(value) {
13 | if (_this.status === 'pending') {
14 | _this.status = 'fulfilled'
15 | _this.value = value
16 | //-----------add--------------
17 | _this.onFulfilledCallbacks.forEach(function (fn) {
18 | fn()
19 | })
20 |
21 | }
22 | }
23 |
24 | function reject(reason) {
25 | if (_this.status === 'pending') {
26 | _this.status = 'rejected'
27 | _this.reason = reason
28 |
29 | //-----------add--------------
30 | _this.onRejectedCallbacks.forEach(function (fn) {
31 | fn()
32 | })
33 | }
34 | }
35 |
36 | executor(function (value) {
37 | resolve(value)
38 | }, function (reason) {
39 | reject(reason)
40 | })
41 | }
42 |
43 | Promise.prototype.then = function (onFulfilled, onRejected) {
44 |
45 | let _this = this
46 |
47 | if (_this.status == 'fulfilled') {
48 | onFulfilled(_this.value)
49 | }
50 |
51 | if (_this.status == 'rejected') {
52 | onRejected(_this.reason)
53 | }
54 |
55 | //-----------add------------
56 | if (_this.status == 'pending') {
57 |
58 | _this.onFulfilledCallbacks.push(function () {
59 | onFulfilled(_this.value)
60 | })
61 | _this.onRejectedCallbacks.push(function () {
62 | onRejected(_this.reason)
63 | })
64 | }
65 | };
66 |
67 | //-------------test code--------------
68 |
69 | (function (type) {
70 | return [() => {
71 | }, () => {
72 |
73 | var promise1 = new Promise((resolve, reject) => {
74 | setTimeout(function () {
75 | //resolve('test simplePromise resolve')
76 | reject('test simplePromise reject')
77 | }, 1000)
78 | })
79 |
80 | promise1.then(function (value) {
81 | console.log('success:', value)
82 | }, function (reason) {
83 | console.log('failed:', reason)
84 | })
85 |
86 | }][type]
87 | })(1)()
88 |
89 |
--------------------------------------------------------------------------------
/prototype/promise_1.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 |
3 | let _this = this
4 | _this.status = 'pending'
5 | _this.value = null
6 | _this.reason = null
7 |
8 | function resolve(value) {
9 | if (_this.status === 'pending') {
10 | _this.status = 'fulfilled'
11 | _this.value = value
12 | }
13 | }
14 |
15 | function reject(reason) {
16 | if (_this.status === 'pending') {
17 | _this.status = 'rejected'
18 | _this.reason = reason
19 | }
20 | }
21 |
22 | executor(function (value) {
23 | resolve(value)
24 | }, function (reason) {
25 | reject(reason)
26 | })
27 | }
28 |
29 | Promise.prototype.then = function (onFulfilled, onRejected) {
30 |
31 | let _this = this
32 |
33 | if (_this.status == 'fulfilled') {
34 | onFulfilled(_this.value)
35 | }
36 |
37 | if (_this.status == 'rejected') {
38 | onRejected(_this.reason)
39 | }
40 | };
41 |
42 |
43 | //-------------test code--------------
44 |
45 | (function (type) {
46 | return [() => {
47 | }, () => {
48 | //-------------------normal
49 | var promise1 = new Promise((resolve, reject) => {
50 | resolve('test simplePromise resolve')
51 | //reject('test simplePromise reject')
52 | })
53 |
54 | promise1.then(function (value) {
55 | console.log('success:', value)
56 | }, function (reason) {
57 | console.log('failed:', reason)
58 | })
59 |
60 | }, () => {
61 | //Q-------------------without Async
62 | var promise2 = new Promise((resolve, reject) => {
63 | setTimeout(function () {
64 | resolve('test simplePromise resolve')
65 | }, 100)
66 | })
67 | promise2.then(function (value) {
68 | console.log('success:', value)
69 | }, function (reason) {
70 | console.log('failed:', reason)
71 | })
72 |
73 | }, () => {
74 | //Q-------------------without Chain
75 | var promise3 = new Promise((resolve, reject) => {
76 | resolve('test simplePromise resolve')
77 | })
78 | promise3.then(function (value) {
79 | console.log('success:', value)
80 | }, function (reason) {
81 | console.log('failed:', reason)
82 | }).then(function (value) {
83 | console.log('success:', value)
84 | }, function (reason) {
85 | console.log('failed:', reason)
86 | })
87 | }][type]
88 | })(1)()
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/prototype/promise_withCatchError_4.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 | //add ----
3 | if (!(this instanceof Promise)) {
4 | return new Promise(executor);
5 | }
6 |
7 | //add
8 | if (typeof executor !== 'function') {
9 | throw new TypeError('Promise executor is not a function');
10 | }
11 |
12 | let _this = this
13 | _this.status = 'pending'
14 | _this.value = null
15 | _this.reason = null
16 | _this.onFulfilledCallbacks=[]
17 | _this.onRejectedCallbacks=[]
18 |
19 | function resolve(value) {
20 | if(_this.status === 'pending'){
21 | _this.status = 'fulfilled'
22 | _this.value = value
23 | _this.onFulfilledCallbacks.forEach(function(fn){
24 | fn()
25 | })
26 | }
27 | }
28 |
29 | function reject(reason) {
30 | if(_this.status === 'pending'){
31 | _this.status = 'rejected'
32 | _this.reason = reason
33 | _this.onRejectedCallbacks.forEach(function(fn){
34 | fn()
35 | })
36 | }
37 | }
38 | //add
39 | try{
40 | executor(function (value) {
41 | resolve(value)
42 | }, function (reason) {
43 | reject(reason)
44 | })
45 | }catch(e){
46 | reject(e)
47 | }
48 |
49 | }
50 |
51 | Promise.prototype.then = function (onFulfilled, onRejected) {
52 |
53 | let _this = this
54 | let newPromise
55 | if (_this.status == 'fulfilled') {
56 | newPromise = new Promise(function(resolve,reject){
57 | //add
58 | try{
59 | let x = onFulfilled(_this.value)
60 | resolve(x)
61 | }catch(e){
62 | reject(e)
63 | }
64 |
65 | })
66 | }
67 |
68 | if (_this.status == 'rejected') {
69 | newPromise = new Promise(function(resolve,reject){
70 | //add
71 | try{
72 | let x = onRejected(_this.reason)
73 | resolve(x)
74 | }catch(e){
75 | reject(e)
76 | }
77 |
78 | })
79 | }
80 |
81 | if (_this.status == 'pending'){
82 | newPromise = new Promise(function(resolve,reject){
83 |
84 | _this.onFulfilledCallbacks.push(function(){
85 | //add
86 | try{
87 | let x = onFulfilled(_this.value)
88 | resolve(x)
89 | }catch(e){
90 | reject(e)
91 | }
92 | })
93 |
94 | _this.onRejectedCallbacks.push(function(){
95 | //add
96 | try{
97 | let x = onRejected(_this.reason)
98 | resolve(x)
99 | }catch(e){
100 | reject(e)
101 | }
102 | })
103 |
104 | })
105 | }
106 | return newPromise
107 | };
108 |
109 | //-------------test code--------------
110 | (function(type){
111 |
112 | return [()=>{
113 | },()=>{
114 | //----------normal catch error
115 | let promise1 = new Promise((resolve,reject) => {
116 | throw new Error('error')
117 | })
118 | promise1.then((value)=>{
119 | console.log('success:',value)
120 | },(reason)=>{
121 | console.log('reject:',reason)
122 | })
123 | },()=>{
124 | //2can't transmit value
125 | new Promise((resolve,reject)=>{
126 | resolve(1)
127 | }).then().then().then((value)=>{
128 | console.log(value)
129 | },(reason)=>{console.log(reason)})
130 | }][type]
131 | })(``)()
132 |
133 | module.exports = Promise
--------------------------------------------------------------------------------
/testPromise.js:
--------------------------------------------------------------------------------
1 | // var SPromise = require('./PPT1_simplePromise_withcatchError_4')
2 | //
3 | // new SPromise(resolve => {
4 | // console.log(1);
5 | // resolve(3);
6 | // new SPromise((resolve) => {
7 | // resolve()
8 | // }).then(() => console.log(4))
9 | // }).then(num => {
10 | // console.log(num)
11 | // });
12 | //
13 | // console.log(2)
14 | // setTimeout(()=>{
15 | // console.log(5)
16 | // })
17 | // new SPromise(resolve => {
18 | // console.log(1);
19 | // resolve(3);
20 | // new SPromise((resolve) => {
21 | // resolve()
22 | // }).then(() => console.log(4))
23 | // }).then(num => {
24 | // console.log(num)
25 | // });
26 | //
27 | // console.log(2)
28 |
29 |
30 | // new Promise((resolve,reject)=>{
31 | // resolve(new Promise((resolve,reject)=>{
32 | // resolve(1)
33 | // }))
34 | // }).then((value)=>{
35 | // console.log(value)
36 | // },(reason)=>{
37 | // console.log(reason)
38 | // })
39 |
40 | //--------testCode-----------
41 |
42 | (function (type) {
43 |
44 | return [() => {
45 | }, ()=>{
46 |
47 | //5.2
48 | var promise2 = new Promise((resolve,reject) => {
49 | setTimeout(function(){
50 | resolve('test simplePromise resolve')
51 | },100)
52 | })
53 |
54 | setTimeout(() => {
55 | promise2.then(function(value){
56 | console.log('success:',value)
57 | },function(reason){
58 | console.log('failed:',reason)
59 | })
60 |
61 | console.log('end')
62 | }, 200);
63 |
64 | },() => {
65 | //6.2 //primary
66 | setTimeout(() => {
67 | console.log(5)
68 | })
69 | new Promise(resolve => {
70 | console.log(1);
71 | resolve(3);
72 | new Promise((resolve) => {
73 | resolve()
74 | }).then(() => console.log(4))
75 | }).then(num => {
76 | console.log(num)
77 | });
78 |
79 | console.log(2)
80 |
81 | }, () => {
82 | //6.settimeout
83 | var Promise = require('./prototype/promise_async_then_6')
84 |
85 | setTimeout(() => {
86 | console.log(5)
87 | })
88 | new Promise(resolve => {
89 | console.log(1);
90 | resolve(3);
91 | new Promise((resolve) => {
92 | resolve()
93 | }).then(() => console.log(4))
94 | }).then(num => {
95 | console.log(num)
96 | });
97 |
98 | console.log(2)
99 |
100 | }, () => {
101 | //3.nextTick
102 | var Promise = require('./prototype/promise_nextTick_7')
103 |
104 | setTimeout(() => {
105 | console.log(5)
106 | })
107 | new Promise(resolve => {
108 | console.log(1);
109 | resolve(3);
110 | new Promise((resolve) => {
111 | resolve()
112 | }).then(() => console.log(4))
113 | }).then(num => {
114 | console.log(num)
115 | });
116 |
117 | console.log(2)
118 |
119 | }, () => {
120 | //4.transmit value: 6 not work
121 | var Promise = require('./prototype/promise_nextTick_7')
122 |
123 | var p = new Promise(resolve=> {
124 | resolve(3);
125 | })
126 | p.then().then().then((value) => {
127 | console.log(value)
128 | });
129 | },() => {
130 | //5.transmit value: 7 ok
131 | var Promise = require('./prototype/promise_transmit_value_5')
132 |
133 | var p = new Promise(resolve => {
134 | resolve(3);
135 | })
136 | p.then().then().then((value) => {
137 | console.log(value)
138 | });
139 | }][type]
140 |
141 | }(2)())
--------------------------------------------------------------------------------
/prototype/promise_chain_3.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 |
3 | let _this = this
4 |
5 | _this.status = 'pending'
6 | _this.value = null
7 | _this.reason = null
8 | _this.onFulfilledCallbacks=[]
9 | _this.onRejectedCallbacks=[]
10 |
11 |
12 | function resolve(value) {
13 | if(_this.status === 'pending'){
14 | _this.status = 'fulfilled'
15 | _this.value = value
16 | _this.onFulfilledCallbacks.forEach(function(fn){
17 | fn()
18 | })
19 |
20 | }
21 | }
22 |
23 | function reject(reason) {
24 | if(_this.status === 'pending'){
25 | _this.status = 'rejected'
26 | _this.reason = reason
27 | _this.onRejectedCallbacks.forEach(function(fn){
28 | fn()
29 | })
30 | }
31 | }
32 |
33 | executor(function (value) {
34 | resolve(value)
35 | }, function (reason) {
36 | reject(reason)
37 | })
38 | }
39 |
40 | Promise.prototype.then = function (onFulfilled, onRejected) {
41 |
42 | let _this = this
43 | let newPromise
44 | if (_this.status == 'fulfilled') {
45 | //add
46 | newPromise = new Promise(function(resolve,reject){
47 | let x = onFulfilled(_this.value)
48 | resolve(x)
49 | })
50 | }
51 |
52 | //不论 promise1 被 reject 还是被 resolve 时 newPromise 都会被 resolve,只有出现异常时才会被 rejected
53 | if (_this.status == 'rejected') {
54 | //add
55 | newPromise = new Promise(function(resolve,reject){
56 | let x = onRejected(_this.reason)
57 | resolve(x) //为什么rejected了还resolve呢?
58 | })
59 | }
60 |
61 | if (_this.status == 'pending'){
62 | //add
63 | newPromise = new Promise(function(resolve,reject){
64 | _this.onFulfilledCallbacks.push(function(){
65 | let x = onFulfilled(_this.value)
66 | resolve(x)
67 | })
68 |
69 | _this.onRejectedCallbacks.push(function(){
70 | let x = onRejected(_this.reason)
71 | resolve(x)
72 | })
73 | })
74 | }
75 | return newPromise
76 | };
77 |
78 |
79 | //-------------test code--------------
80 |
81 | (function(type){
82 |
83 | return [()=>{},()=>{
84 | //-------------------normal
85 | let promise1 = new Promise((resolve,reject) => {
86 | resolve('test simplePromise resolve')
87 | })
88 |
89 | promise1.then(function(value){
90 | console.log('success:',value)
91 | return 'success next'
92 | },function(reason){
93 | console.log('failed:',reason)
94 | }).then(function(value){
95 | console.log('success:',value)
96 | },function(reason){
97 | console.log('failed:',reason)
98 | })
99 | },()=>{
100 | //-------------------normal reject
101 | let promise2 = new Promise((resolve,reject) => {
102 | reject('test simplePromise reject')
103 | })
104 |
105 | promise2.then(function(value){
106 | console.log('success:',value)
107 | },function(reason){
108 | console.log('failed:',reason)
109 | return 'failed next'
110 | }).then(function(value){
111 | console.log('success:',value)
112 | },function(reason){
113 | console.log('failed:',reason)
114 | })
115 | },()=>{
116 | //Q-----------------can't catch error
117 | let promise3 = new Promise((resolve,reject) => {
118 | throw new Error('error')
119 | })
120 | promise3.then((value)=>{
121 | console.log('success:',value)
122 | },(reason)=>{
123 | console.log('reject:',reason)
124 | })
125 | }][type]
126 | })(3)()
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/prototype/promise_transmit_value_5.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 | if (!(this instanceof Promise)) {
3 | return new Promise(executor);
4 | }
5 |
6 | if (typeof executor !== 'function') {
7 | throw new TypeError('Promise executor is not a function');
8 | }
9 |
10 | let _this = this
11 | _this.status = 'pending'
12 | _this.value = null
13 | _this.reason = null
14 | _this.onFulfilledCallbacks=[]
15 | _this.onRejectedCallbacks=[]
16 |
17 | function resolve(value) {
18 | if(_this.status === 'pending'){
19 | _this.status = 'fulfilled'
20 | _this.value = value
21 | _this.onFulfilledCallbacks.forEach(function(fn){
22 | fn()
23 | })
24 | }
25 | }
26 |
27 | function reject(reason) {
28 | if(_this.status === 'pending'){
29 | _this.status = 'rejected'
30 | _this.reason = reason
31 | _this.onRejectedCallbacks.forEach(function(fn){
32 | fn()
33 | })
34 | }
35 | }
36 |
37 | try{
38 | executor(function (value) {
39 | resolve(value)
40 | }, function (reason) {
41 | reject(reason)
42 | })
43 | }catch(e){
44 | reject(e)
45 | }
46 |
47 | }
48 |
49 | Promise.prototype.then = function (onFulfilled, onRejected) {
50 |
51 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
52 | return value
53 | }
54 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
55 | throw err
56 | }
57 |
58 | let _this = this
59 | let newPromise
60 | if (_this.status == 'fulfilled') {
61 | newPromise = new Promise(function(resolve,reject){
62 | //add
63 | try{
64 | let x = onFulfilled(_this.value)
65 | resolve(x)
66 | }catch(e){
67 | reject(e)
68 | }
69 |
70 | })
71 | }
72 |
73 | if (_this.status == 'rejected') {
74 | newPromise = new Promise(function(resolve,reject){
75 | //add
76 | try{
77 | let x = onRejected(_this.reason)
78 | resolve(x)
79 | }catch(e){
80 | reject(e)
81 | }
82 |
83 | })
84 | }
85 |
86 | if (_this.status == 'pending'){
87 | newPromise = new Promise(function(resolve,reject){
88 |
89 | _this.onFulfilledCallbacks.push(function(){
90 | //add
91 | try{
92 | let x = onFulfilled(_this.value)
93 | resolve(x)
94 | }catch(e){
95 | reject(e)
96 | }
97 | })
98 |
99 | _this.onRejectedCallbacks.push(function(){
100 | //add
101 | try{
102 | let x = onRejected(_this.reason)
103 | resolve(x)
104 | }catch(e){
105 | reject(e)
106 | }
107 | })
108 |
109 | })
110 | }
111 | return newPromise
112 | };
113 |
114 | //-------------test code--------------
115 | (function(type){
116 |
117 | return [()=>{
118 | },()=>{
119 | //--------normal
120 | new Promise((resolve,reject)=>{
121 | resolve(1)
122 | }).then().then().then((value)=>{
123 | console.log(value)
124 | },(reason)=>{console.log(reason)})
125 | },()=>{
126 |
127 | //2 Unhandle situation when sync call onFulfill and onReject
128 |
129 | var promise2 = new Promise((resolve,reject) => {
130 | setTimeout(function(){
131 | resolve('test simplePromise resolve')
132 | },100)
133 | })
134 |
135 | setTimeout(() => {
136 | promise2.then(function(value){
137 | console.log('success:',value)
138 | },function(reason){
139 | console.log('failed:',reason)
140 | })
141 |
142 | console.log('end')
143 | }, 200);
144 |
145 | // var promise2 = new Promise((resolve,reject) => {
146 | // resolve('test simplePromise resolve')
147 | // })
148 | //
149 | // promise2.then(function(value){
150 | // console.log('success:',value)
151 | // },function(reason){
152 | // console.log('failed:',reason)
153 | // })
154 |
155 | // console.log('end')
156 | //5.2
157 |
158 | }][type]
159 | })(2)()
160 |
161 | module.exports = Promise
--------------------------------------------------------------------------------
/prototype/promise_async_then_6.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 |
3 | if (!(this instanceof Promise)) {
4 | return new Promise(executor);
5 | }
6 |
7 | if (typeof executor !== 'function') {
8 | throw new TypeError('Promise executor is not a function');
9 | }
10 |
11 | let _this = this
12 | _this.status = 'pending'
13 | _this.value = null
14 | _this.reason = null
15 | _this.onRejectedCallbacks=[]
16 | _this.onResolvedCallbacks=[]
17 |
18 | function resolve(value) {
19 | if(_this.status === 'pending'){
20 | _this.status = 'resolved'
21 | _this.value = value
22 | _this.onResolvedCallbacks.forEach(function(fn){
23 | fn()
24 | })
25 | }
26 | }
27 |
28 | function reject(reason) {
29 | if(_this.status === 'pending'){
30 | _this.status = 'rejected'
31 | _this.reason = reason
32 | _this.onRejectedCallbacks.forEach(function(fn){
33 | fn()
34 | })
35 | }
36 | }
37 | try{
38 | executor(function (value) {
39 | resolve(value)
40 | }, function (reason) {
41 | reject(reason)
42 | })
43 | }catch(e){
44 | reject(e)
45 | }
46 |
47 | }
48 |
49 | Promise.prototype.then = function (onFulfilled, onRejected) {
50 |
51 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
52 | return value
53 | }
54 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
55 | throw err
56 | }
57 | let _this = this
58 | let newPromise
59 | if (_this.status == 'resolved') {
60 |
61 | newPromise = new Promise(function(resolve,reject){
62 | //add
63 | setTimeout(function () {
64 | try{
65 | let x = onFulfilled(_this.value)
66 | resolve(x)
67 | }catch(e){
68 | reject(e)
69 | }
70 | })
71 |
72 | })
73 | }
74 |
75 | if (_this.status == 'rejected') {
76 | newPromise = new Promise(function(resolve,reject){
77 | //add
78 | setTimeout(function () {
79 | try{
80 | let x = onRejected(_this.reason)
81 | resolve(x)
82 | }catch(e){
83 | reject(e)
84 | }
85 | })
86 |
87 | })
88 | }
89 |
90 | if (_this.status == 'pending'){
91 | newPromise = new Promise(function(resolve,reject){
92 | //add
93 | _this.onResolvedCallbacks.push(function(){
94 | setTimeout(function () {
95 | try {
96 | let x = onFulfilled(_this.value)
97 | resolve(x)
98 | } catch (e) {
99 | reject(e)
100 | }
101 | })
102 | })
103 | //add
104 | _this.onRejectedCallbacks.push(function(){
105 | setTimeout(function () {
106 | try {
107 | let x = onFulfilled(_this.value)
108 | resolve(x)
109 | } catch (e) {
110 | reject(e)
111 | }
112 | })
113 | })
114 |
115 | })
116 | }
117 | return newPromise
118 | };
119 |
120 |
121 | //-------------test code--------------
122 | (function (type) {
123 |
124 | return [() => {
125 | },()=>{
126 | //-----------normal
127 | var promise2 = new Promise((resolve,reject) => {
128 | setTimeout(function(){
129 | resolve('test simplePromise resolve')
130 | },100)
131 | })
132 |
133 | setTimeout(() => {
134 | promise2.then(function(value){
135 | console.log('success:',value)
136 | },function(reason){
137 | console.log('failed:',reason)
138 | })
139 |
140 | console.log('end')
141 | }, 200);
142 | }, () => {
143 | //Q-----------------setTimeout problem
144 | setTimeout(() => {
145 | console.log(5)
146 | })
147 | new Promise(resolve => {
148 | console.log(1);
149 | resolve(3);
150 | new Promise((resolve) => {
151 | resolve()
152 | }).then(() => console.log(4))
153 | }).then(num => {
154 | console.log(num)
155 | });
156 |
157 | console.log(2)
158 | //6.2 testPromise
159 | }][type]
160 |
161 | }(2)())
162 |
163 | module.exports = Promise
--------------------------------------------------------------------------------
/prototype/promise_nextTick_7.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 | if (!(this instanceof Promise)) {
3 | return new Promise(executor);
4 | }
5 |
6 | if (typeof executor !== 'function') {
7 | throw new TypeError('Promise executor is not a function');
8 | }
9 | let _this = this
10 | _this.status = 'pending'
11 | _this.value = null
12 | _this.reason = null
13 | _this.onRejectedCallbacks = []
14 | _this.onResolvedCallbacks = []
15 |
16 | function resolve(value) {
17 | if (_this.status === 'pending') {
18 | _this.status = 'resolved'
19 | _this.value = value
20 | _this.onResolvedCallbacks.forEach(function (fn) {
21 | fn()
22 | })
23 | }
24 |
25 | }
26 |
27 | function reject(reason) {
28 | if (_this.status === 'pending') {
29 | _this.status = 'rejected'
30 | _this.reason = reason
31 | _this.onRejectedCallbacks.forEach(function (fn) {
32 | fn()
33 | })
34 | }
35 | }
36 |
37 | try {
38 | executor(function (value) {
39 | resolve(value)
40 | }, function (reason) {
41 | reject(reason)
42 | })
43 | } catch (e) {
44 | reject(e)
45 | }
46 |
47 | }
48 |
49 | Promise.prototype.then = function (onFulfilled, onRejected) {
50 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
51 | return value
52 | }
53 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
54 | throw err
55 | }
56 |
57 | let _this = this
58 | let newPromise
59 | if (_this.status == 'resolved') {
60 | newPromise = new Promise(function (resolve, reject) {
61 | //add
62 | process.nextTick(function () {
63 | try {
64 | let x = onFulfilled(_this.value)
65 | resolve(x)
66 | } catch (e) {
67 | reject(e)
68 | }
69 | })
70 | })
71 | }
72 |
73 | if (_this.status == 'rejected') {
74 | newPromise = new Promise(function (resolve, reject) {
75 | //add
76 | process.nextTick(function () {
77 | try {
78 | let x = onRejected(_this.reason)
79 | resolve(x)
80 | } catch (e) {
81 | reject(e)
82 | }
83 | })
84 |
85 | })
86 | }
87 |
88 | if (_this.status == 'pending') {
89 | newPromise = new Promise(function (resolve, reject) {
90 | //add
91 | _this.onResolvedCallbacks.push(function(){
92 | process.nextTick(function () {
93 | try {
94 | let x = onFulfilled(_this.value)
95 | resolve(x)
96 | } catch (e) {
97 | reject(e)
98 | }
99 | })
100 | })
101 | //add
102 | _this.onRejectedCallbacks.push(function(){
103 | process.nextTick(function () {
104 | try {
105 | let x = onFulfilled(_this.value)
106 | resolve(x)
107 | } catch (e) {
108 | reject(e)
109 | }
110 | })
111 | })
112 |
113 | })
114 | }
115 | return newPromise
116 | };
117 | //-------------test code--------------
118 | (function (type) {
119 |
120 | return [() => {
121 | },()=>{
122 | //-----------------normal
123 | setTimeout(() => {
124 | console.log(5)
125 | })
126 | new Promise(resolve => {
127 | console.log(1);
128 | resolve(3);
129 | new Promise((resolve) => {
130 | resolve()
131 | }).then(() => console.log(4))
132 | }).then(num => {
133 | console.log(num)
134 | });
135 |
136 | console.log(2)
137 | }, () => {
138 | //Q---------------
139 | new Promise((resolve, reject) => {
140 | resolve(new Promise((resolve) => {
141 | resolve(1)
142 | }))
143 | }).then((value) => {
144 | console.log('success1:', value)
145 | }, (reason) => {
146 | console.log('failed1:', reason)
147 | })
148 |
149 | //Q--------------thenable
150 | new Promise((resolve, reject) => {
151 | resolve({
152 | then: (resolve,reject)=>{
153 | resolve(1)
154 | }
155 | })
156 | }).then((value) => {
157 | console.log('success2:', value)
158 | }, (reason) => {
159 | console.log('failed2:', reason)
160 | })
161 |
162 | //问题:resolve是自己,thenable,或者是promise,thenable
163 |
164 | }][type]
165 |
166 | }(2)())
167 | module.exports = Promise
--------------------------------------------------------------------------------
/prototype/promise_without_called_8.js:
--------------------------------------------------------------------------------
1 |
2 | function Promise(executor) {
3 | if (!(this instanceof Promise)) {
4 | return new Promise(executor);
5 | }
6 |
7 | if (typeof executor !== 'function') {
8 | throw new TypeError('Promise executor is not a function');
9 | }
10 |
11 | let _this = this
12 | _this.status = 'pending'
13 | _this.value = null
14 | _this.reason = null
15 | _this.onRejectedCallbacks = []
16 | _this.onResolvedCallbacks = []
17 |
18 | function resolve(value) {
19 | resolvePromise(_this,value,fulfill,reject)
20 | }
21 |
22 | function fulfill(value){ //只接收普通值
23 | if (_this.status === 'pending') {
24 | _this.status = 'resolved'
25 | _this.value = value
26 | _this.onResolvedCallbacks.forEach(function (fn) {
27 | fn()
28 | })
29 | }
30 | }
31 |
32 | function reject(reason) {
33 | if (_this.status === 'pending') {
34 | _this.status = 'rejected'
35 | _this.reason = reason
36 | _this.onRejectedCallbacks.forEach(function (fn) {
37 | fn()
38 | })
39 | }
40 | }
41 |
42 |
43 |
44 | try {
45 | executor(function (value) {
46 | resolve(value)
47 | }, function (reason) {
48 | reject(reason)
49 | })
50 | } catch (e) {
51 | reject(e)
52 | }
53 |
54 | }
55 |
56 |
57 | function resolvePromise(promise,x,fulfill,reject) {
58 |
59 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
60 | return reject(new TypeError('循环引用了'))
61 | }
62 | //2.3.2
63 | if (x instanceof Promise) {
64 | //2.3.2.1
65 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
66 | x.then(function(y) {
67 | resolvePromise(promise, y, fulfill, reject)
68 | }, reject)
69 | } else {
70 | //2.3.2.2 2.3.2.3
71 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
72 | x.then(fulfill, reject)
73 | }
74 | return
75 | }
76 | fulfill(x)
77 | }
78 |
79 | Promise.prototype.then = function (onFulfilled, onRejected) {
80 |
81 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
82 | return value
83 | }
84 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
85 | throw err
86 | }
87 |
88 | let _this = this
89 | let newPromise
90 | if (_this.status === 'resolved') {
91 | newPromise = new Promise(function (resolve, reject) {
92 | process.nextTick(function () {
93 | try {
94 | let x = onFulfilled(_this.value)
95 | resolve(x)
96 | } catch (e) {
97 | reject(e)
98 | }
99 | })
100 | })
101 | }
102 |
103 | if (_this.status === 'rejected') {
104 | newPromise = new Promise(function (resolve, reject) {
105 | process.nextTick(function () {
106 | try {
107 | let x = onRejected(_this.reason)
108 | resolve(x)
109 | } catch (e) {
110 | reject(e)
111 | }
112 | })
113 | })
114 | }
115 |
116 | if (_this.status === 'pending') {
117 | newPromise = new Promise(function (resolve, reject) {
118 |
119 | _this.onResolvedCallbacks.push(function () {
120 | process.nextTick(function () {
121 | try {
122 | let x = onFulfilled(_this.value)
123 | resolve(x)
124 | } catch (e) {
125 | reject(e)
126 | }
127 | })
128 |
129 | })
130 |
131 |
132 | _this.onRejectedCallbacks.push(function () {
133 | process.nextTick(function () {
134 | try {
135 | let x = onRejected(_this.reason)
136 | resolve(x)
137 | } catch (e) {
138 | reject(e)
139 | }
140 | })
141 | })
142 |
143 | })
144 | }
145 | return newPromise
146 | };
147 |
148 | //-------------test code--------------
149 | (function (type) {
150 |
151 | return [() => {}, ()=>{
152 | //--------------- normal
153 | new Promise((resolve, reject) => {
154 | resolve(new Promise((resolve) => {
155 | resolve(1)
156 | }))
157 | }).then((value) => {
158 | console.log('success1:', value)
159 | }, (reason) => {
160 | console.log('failed1:', reason)
161 | })
162 |
163 | }, ()=>{
164 |
165 | //Q--------------withoutcalled
166 | new Promise((resolve, reject) => {
167 | resolve(new Promise((resolve) => {
168 | resolve(1)
169 | }))
170 | reject('error')
171 | }).then((value) => {
172 | console.log('success:', value)
173 | }, (reason) => {
174 | console.log('failed:', reason)
175 | })
176 |
177 | },][type]
178 |
179 | }(1)())
180 |
181 |
182 | module.exports = Promise
--------------------------------------------------------------------------------
/prototype/promise_with_called_9.js:
--------------------------------------------------------------------------------
1 |
2 | function Promise(executor) {
3 | if (!(this instanceof Promise)) {
4 | return new Promise(executor);
5 | }
6 |
7 | if (typeof executor !== 'function') {
8 | throw new TypeError('Promise executor is not a function');
9 | }
10 |
11 | let _this = this
12 | _this.status = 'pending'
13 | _this.value = null
14 | _this.reason = null
15 | _this.onRejectedCallbacks = []
16 | _this.onResolvedCallbacks = []
17 |
18 | function resolve(value) {
19 | resolvePromise(_this,value,fulfill,reject)
20 | }
21 |
22 | function fulfill(value){ //只接收普通值
23 | if (_this.status === 'pending') {
24 | _this.status = 'resolved'
25 | _this.value = value
26 | _this.onResolvedCallbacks.forEach(function (fn) {
27 | fn()
28 | })
29 | }
30 | }
31 |
32 | function reject(reason) {
33 | if (_this.status === 'pending') {
34 | _this.status = 'rejected'
35 | _this.reason = reason
36 | _this.onRejectedCallbacks.forEach(function (fn) {
37 | fn()
38 | })
39 | }
40 | }
41 |
42 |
43 |
44 | try {
45 | let called = false
46 | executor(function (value) {
47 | if(called) return
48 | called = true
49 | resolve(value)
50 | }, function (reason) {
51 | if(called) return
52 | called = true
53 | reject(reason)
54 | })
55 | } catch (e) {
56 | reject(e)
57 | }
58 |
59 | }
60 |
61 | function resolvePromise(promise,x,fulfill,reject) {
62 |
63 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
64 | return reject(new TypeError('循环引用了'))
65 | }
66 | //2.3.2
67 | if (x instanceof Promise) {
68 | //2.3.2.1
69 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
70 | x.then(function(y) {
71 | resolvePromise(promise, y, fulfill, reject)
72 | }, reject)
73 | } else {
74 | //2.3.2.2 2.3.2.3
75 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
76 | x.then(fulfill, reject)
77 | }
78 | return
79 | }
80 | fulfill(x)
81 | }
82 |
83 | Promise.prototype.then = function (onFulfilled, onRejected) {
84 |
85 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
86 | return value
87 | }
88 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
89 | throw err
90 | }
91 |
92 | let _this = this
93 | let newPromise
94 | if (_this.status === 'resolved') {
95 | newPromise = new Promise(function (resolve, reject) {
96 | process.nextTick(function () {
97 | try {
98 | let x = onFulfilled(_this.value)
99 | resolve(x)
100 | } catch (e) {
101 | reject(e)
102 | }
103 | })
104 | })
105 | }
106 |
107 | if (_this.status === 'rejected') {
108 | newPromise = new Promise(function (resolve, reject) {
109 | process.nextTick(function () {
110 | try {
111 | let x = onRejected(_this.reason)
112 | resolve(x)
113 | } catch (e) {
114 | reject(e)
115 | }
116 | })
117 | })
118 | }
119 |
120 | if (_this.status === 'pending') {
121 | newPromise = new Promise(function (resolve, reject) {
122 |
123 | _this.onResolvedCallbacks.push(function () {
124 | process.nextTick(function () {
125 | try {
126 | let x = onFulfilled(_this.value)
127 | resolve(x)
128 | } catch (e) {
129 | reject(e)
130 | }
131 | })
132 |
133 | })
134 |
135 |
136 | _this.onRejectedCallbacks.push(function () {
137 | process.nextTick(function () {
138 | try {
139 | let x = onRejected(_this.reason)
140 | resolve(x)
141 | } catch (e) {
142 | reject(e)
143 | }
144 | })
145 | })
146 |
147 | })
148 | }
149 | return newPromise
150 | };
151 |
152 |
153 | //-------------test code--------------
154 | (function (type) {
155 |
156 | return [() => {}, () => {
157 | //---------normal
158 | new Promise((resolve, reject) => {
159 | resolve(new Promise((resolve) => {
160 | resolve(1)
161 | }))
162 | reject('error')
163 | }).then((value) => {
164 | console.log('success:', value)
165 | }, (reason) => {
166 | console.log('failed:', reason)
167 | })
168 | }, () => {
169 | //Q---------can't resolve thenable
170 | new Promise((resolve, reject) => {
171 | resolve({
172 | then: (resolve,reject)=>{
173 | resolve(1)
174 | }
175 | })
176 | }).then((value) => {
177 | console.log('success:', value)
178 | }, (reason) => {
179 | console.log('failed:', reason)
180 | })
181 | }][type]
182 |
183 | }(1)())
184 |
185 | module.exports = Promise
--------------------------------------------------------------------------------
/prototype/promise_final_10.js:
--------------------------------------------------------------------------------
1 | function Promise(executor) {
2 | if (!(this instanceof Promise)) {
3 | return new Promise(executor);
4 | }
5 |
6 | if (typeof executor !== 'function') {
7 | throw new TypeError('Promise executor is not a function');
8 | }
9 |
10 | let _this = this
11 | _this.status = 'pending'
12 | _this.value = null
13 | _this.reason = null
14 | _this.onRejectedCallbacks = []
15 | _this.onResolvedCallbacks = []
16 |
17 | function resolve(value) {
18 | resolvePromise(_this,value,fulfill,reject)
19 | }
20 |
21 | function fulfill(value){ //只接收普通值
22 | if (_this.status === 'pending') {
23 | _this.status = 'resolved'
24 | _this.value = value
25 | _this.onResolvedCallbacks.forEach(function (fn) {
26 | fn()
27 | })
28 | }
29 | }
30 |
31 | function reject(reason) {
32 | if (_this.status === 'pending') {
33 | _this.status = 'rejected'
34 | _this.reason = reason
35 | _this.onRejectedCallbacks.forEach(function (fn) {
36 | fn()
37 | })
38 | }
39 | }
40 |
41 |
42 |
43 | try {
44 | let called = false
45 | executor(function (value) {
46 | if(called) return
47 | called = true
48 | resolve(value)
49 | }, function (reason) {
50 | if(called) return
51 | called = true
52 | reject(reason)
53 | })
54 | } catch (e) {
55 | reject(e)
56 | }
57 |
58 | }
59 |
60 | function resolvePromise(promise,x,fulfill,reject) {
61 |
62 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
63 | return reject(new TypeError('循环引用了'))
64 | }
65 |
66 | //2.3.2 x如果是一个promise
67 | if (x instanceof Promise) {
68 | //2.3.2.1
69 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
70 | x.then(function(y) {
71 | resolvePromise(promise, y, fulfill, reject)
72 | },reject)
73 | } else {
74 | //2.3.2.2 , 2.3.2.3
75 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
76 | x.then(fulfill, reject)
77 | }
78 | return;
79 | }
80 | let called = false;
81 | //2.3.3
82 | //x 是一个thenable
83 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
84 | try {
85 | //2.3.3.1
86 | let then = x.then;
87 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
88 | then.call(x,(y)=>{
89 | if (called) return
90 | called = true
91 | resolvePromise(promise,y,fulfill,reject)
92 | },(err)=>{
93 | if (called) return
94 | called = true
95 | reject(err)
96 | })
97 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
98 | fulfill(x)
99 | }
100 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
101 | if (called) return
102 | called = true;
103 | reject(e);
104 | }
105 | }else{//2.3.3.4,x是一个普通值
106 | fulfill(x)
107 | }
108 | }
109 | Promise.prototype.then = function (onFulfilled, onRejected) {
110 |
111 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
112 | return value
113 | }
114 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
115 | throw err
116 | }
117 |
118 | let _this = this
119 | let newPromise
120 | if (_this.status === 'resolved') {
121 | newPromise = new Promise(function (resolve, reject) {
122 | process.nextTick(function () {
123 | try {
124 | let x = onFulfilled(_this.value)
125 | resolve(x)
126 | } catch (e) {
127 | reject(e)
128 | }
129 | })
130 | })
131 | }
132 |
133 | if (_this.status === 'rejected') {
134 | newPromise = new Promise(function (resolve, reject) {
135 | process.nextTick(function () {
136 | try {
137 | let x = onRejected(_this.reason)
138 | resolve(x)
139 | } catch (e) {
140 | reject(e)
141 | }
142 | })
143 | })
144 | }
145 |
146 | if (_this.status === 'pending') {
147 | newPromise = new Promise(function (resolve, reject) {
148 |
149 | _this.onResolvedCallbacks.push(function () {
150 | process.nextTick(function () {
151 | try {
152 | let x = onFulfilled(_this.value)
153 | resolve(x)
154 | } catch (e) {
155 | reject(e)
156 | }
157 | })
158 |
159 | })
160 |
161 |
162 | _this.onRejectedCallbacks.push(function () {
163 | process.nextTick(function () {
164 | try {
165 | let x = onRejected(_this.reason)
166 | resolve(x)
167 | } catch (e) {
168 | reject(e)
169 | }
170 | })
171 | })
172 |
173 | })
174 | }
175 | return newPromise
176 | }
177 |
178 | Promise.deferred = Promise.defer = function () {
179 | var dfd = {}
180 | dfd.promise = new Promise(function (resolve, reject) {
181 | dfd.resolve = resolve
182 | dfd.reject = reject
183 | })
184 | return dfd
185 | };
186 |
187 | //-------------test code--------------
188 | (function (type) {
189 |
190 | return [() => {}, () => {
191 |
192 | new Promise((resolve, reject) => {
193 | resolve({
194 | then: (resolve,reject)=>{
195 | resolve(1)
196 | }
197 | })
198 | }).then((value) => {
199 | console.log('success:', value)
200 | }, (reason) => {
201 | console.log('failed:', reason)
202 | })
203 |
204 | }][type]
205 |
206 | }(1)())
207 |
208 | module.exports = Promise
--------------------------------------------------------------------------------
/lib/promise.js:
--------------------------------------------------------------------------------
1 | var asyncCall = (process && process.nextTick) || setImmediate || function (callback) {
2 | if (typeof callback !== 'function')
3 | throw new TypeError('callback is not a function');
4 | var Mutation = window.MutationObserver || window.WebKitMutationObserver;
5 | var observer = new Mutation(callback);
6 | var element = document.createTextNode('');
7 | observer.observe(element, {
8 | characterData: true
9 | });
10 | element.data = 1;
11 | } || function (callback) {
12 | if (typeof callback !== 'function')
13 | throw new TypeError('callback is not a function');
14 | setTimeout(callback, 0);
15 | };
16 |
17 | function Promise(executor) {
18 | if (!(this instanceof Promise)) {
19 | return new Promise(executor);
20 | }
21 |
22 | if (typeof executor !== 'function') {
23 | throw new TypeError('Promise executor is not a function');
24 | }
25 |
26 | let _this = this
27 | _this.status = 'pending'
28 | _this.value = null
29 | _this.reason = null
30 | _this.onRejectedCallbacks = []
31 | _this.onResolvedCallbacks = []
32 |
33 | function resolve(value) {
34 | resolvePromise(_this,value,fulfill,reject)
35 | }
36 |
37 | function fulfill(value){ //只接收普通值
38 | if (_this.status === 'pending') {
39 | _this.status = 'resolved'
40 | _this.value = value
41 | _this.onResolvedCallbacks.forEach(function (fn) {
42 | fn()
43 | })
44 | }
45 | }
46 |
47 | function reject(reason) {
48 | if (_this.status === 'pending') {
49 | _this.status = 'rejected'
50 | _this.reason = reason
51 | _this.onRejectedCallbacks.forEach(function (fn) {
52 | fn()
53 | })
54 | }
55 | }
56 |
57 |
58 | try {
59 | let called = false
60 | executor(function (value) {
61 | if(called) return
62 | called = true
63 | resolve(value)
64 | }, function (reason) {
65 | if(called) return
66 | called = true
67 | reject(reason)
68 | })
69 | } catch (e) {
70 | reject(e)
71 | }
72 |
73 | }
74 |
75 | function resolvePromise(promise,x,fulfill,reject) {
76 |
77 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
78 | return reject(new TypeError('循环引用了'))
79 | }
80 |
81 | //2.3.2 x如果是一个promise
82 | if (x instanceof Promise) {
83 | //2.3.2.1
84 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
85 | x.then(function(y) {
86 | resolvePromise(promise, y, fulfill, reject)
87 | },reject)
88 | } else {
89 | //2.3.2.2 , 2.3.2.3
90 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
91 | x.then(fulfill, reject)
92 | }
93 | return;
94 | }
95 | let called = false;
96 | //2.3.3
97 | //x 是一个thenable
98 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
99 | try {
100 | //2.3.3.1
101 | let then = x.then;
102 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
103 | then.call(x,(y)=>{
104 | if (called) return
105 | called = true
106 | resolvePromise(promise,y,fulfill,reject)
107 | },(err)=>{
108 | if (called) return
109 | called = true
110 | reject(err)
111 | })
112 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
113 | fulfill(x)
114 | }
115 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
116 | if (called) return
117 | called = true;
118 | reject(e);
119 | }
120 | }else{//2.3.3.4,x是一个普通值
121 | fulfill(x)
122 | }
123 | }
124 |
125 | Promise.prototype.then = function (onFulfilled, onRejected) {
126 |
127 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
128 | return value
129 | }
130 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
131 | throw err
132 | }
133 |
134 | let _this = this
135 | let newPromise
136 | if (_this.status === 'resolved') {
137 | newPromise = new Promise(function (resolve, reject) {
138 | asyncCall(function () {
139 | try {
140 | let x = onFulfilled(_this.value)
141 | resolve(x)
142 | } catch (e) {
143 | console.log(e)
144 | reject(e)
145 | }
146 | })
147 | })
148 | }
149 |
150 | if (_this.status === 'rejected') {
151 | newPromise = new Promise(function (resolve, reject) {
152 | asyncCall(function () {
153 | try {
154 | let x = onRejected(_this.reason)
155 | resolve(x)
156 | } catch (e) {
157 | reject(e)
158 | }
159 | })
160 | })
161 | }
162 |
163 | if (_this.status === 'pending') {
164 | newPromise = new Promise(function (resolve, reject) {
165 |
166 | _this.onResolvedCallbacks.push(function () {
167 | asyncCall(function () {
168 | try {
169 | let x = onFulfilled(_this.value)
170 | resolve(x)
171 | } catch (e) {
172 | reject(e)
173 | }
174 | })
175 |
176 | })
177 |
178 |
179 | _this.onRejectedCallbacks.push(function () {
180 | asyncCall(function () {
181 | try {
182 | let x = onRejected(_this.reason)
183 | resolve(x)
184 | } catch (e) {
185 | reject(e)
186 | }
187 | })
188 | })
189 |
190 | })
191 | }
192 | return newPromise
193 | }
194 |
195 | Promise.prototype.catch = function(callback){
196 | return this.then(null,callback)
197 | }
198 | Promise.resolve = function(value){
199 | return new Promise(function(resolve,reject){
200 | resolve(value);
201 | })
202 | }
203 | Promise.reject = function(value){
204 | return new Promise(function(resolve,reject){
205 | reject(value);
206 | })
207 | }
208 | Promise.race = function(promise){
209 | return new Promise(function (resolve,reject){
210 | for(var i = 0;i{
11 | getDataB(a,(b)=>{
12 | getDataC(b,(c)=>{
13 | console.log(c)
14 | }))
15 | })
16 | })
17 | ```
18 |
19 | getDataA、getDataB、getDataC都是异步的。getDataB依赖getDataA的结果,getDataC依赖getDataB的结果,三者通过回调的方式来处理依赖关系,可以看到如果依赖关系层级多的话,层级就会越来越深,最终形成`回调地狱`。
20 |
21 | 如果采用Promise的方式,我们可以将一个个过程抽象成Promise,然后将其链式调用,优雅的避开了多层回调的问题。
22 |
23 | ```javascript
24 | const getDataA = function(){
25 | return new Promise((resolve,reject)=>{
26 | resolve(a)
27 | })
28 | }
29 | const getDataB = function(a){
30 | return new Promise((resolve,reject)=>{
31 | resolve(b)
32 | })
33 | }
34 |
35 | const getDataC = function(b){
36 | return new Promise((resolve,reject)=>{
37 | resolve(c)
38 | })
39 | }
40 | getDataA().then(getDataB).then(getDataC).then((c)=>{
41 | console.log(c)
42 | })
43 | ```
44 |
45 | 对比一下,下面的代码是不是更清晰一些,更容易理清楚每一个过程的依赖关系。
46 |
47 | 我们不禁好奇为什么通过这种方式就能解决异步回调?每个Promise里面做了什么?then为什么能链式调用?
48 |
49 | 带着这些疑惑,我们来研究下Promise的原理。从一个Promise雏形开始,通过打补丁的方式,一点一点的实现一个符合规范的Promise。
50 |
51 | ## PromiseA+规范
52 |
53 | 首先来看下规范,[https://promisesaplus.com](https://promisesaplus.com)。如果单纯的看这个规范,容易看的晕头转向,我简单总结了下它的核心点,也就四个:
54 |
55 | 1.Promise是一个状态机,有三种状态`pending`,`fulfilled`,`rejected`。只能从`pending`状态,转换为`fulfilled`或者`rejected`,不可逆转且无第三种状态转换方式。
56 |
57 | 2.必须提供一个then方法用以处理当前值:终值和据因。then接收两个参数onFufilled,onRejected分别处理fulfilled和rejected的结果。
58 |
59 | 3.then方法必须返回一个新的Promise , 便于链式调用。
60 |
61 | 4.Promise中必须包含一个`resolve`方法,能够接受各种类型的值,将其处理成普通值`fulfilled`或者直接`rejected`
62 |
63 | ## Promise雏形
64 |
65 | 根据上面总结的四点,先来实现一个promise的雏形:
66 |
67 | ```javascript
68 | function Promise(executor) {
69 |
70 | let _this = this
71 | _this.status = 'pending'
72 | _this.value = null
73 | _this.reason = null
74 |
75 | function resolve(value) {
76 | if (_this.status === 'pending') {
77 | _this.status = 'fulfilled'
78 | _this.value = value
79 | }
80 | }
81 |
82 | function reject(reason) {
83 | if (_this.status === 'pending') {
84 | _this.status = 'rejected'
85 | _this.reason = reason
86 | }
87 | }
88 | //暂时先不要问为什么这么写,文末分解
89 | executor(function (value) {
90 | resolve(value)
91 | }, function (reason) {
92 | reject(reason)
93 | },)
94 | }
95 |
96 | Promise.prototype.then = function (onFulfilled, onRejected) {
97 | let _this = this
98 |
99 | if (_this.status == 'fulfilled') {
100 | onFulfilled(_this.value)
101 | }
102 |
103 | if (_this.status == 'rejected') {
104 | onRejected(_this.reason)
105 | }
106 | }
107 | ```
108 |
109 | 上面的代码中,Promise里面的东西是很健全的:有改变Promise装态的两个方法resolve(确切的说,这个方法应该叫fulfill,fulfill和resolve是概念是不一样的,后面会解释原因)和reject,有管理状态的status,保存fulfilled状态值的value和rejected拒因的reason,还包含了一个then方法用来处理fulfilled的值和rejected的据因。
110 |
111 | 试验一下效果:
112 |
113 | ```javascript
114 | var promise = new Promise((resolve, reject) => {
115 | resolve('test simplePromise resolve')
116 | })
117 |
118 | promise.then(function (value) {
119 | console.log('success:', value)
120 | }, function (reason) {
121 | console.log('failed:', reason)
122 | })
123 | ```
124 |
125 | 结果:`success:test simplePromise resolve`,基本什么问题,有点promise的样子。
126 |
127 | 来个问题测试一下,`Q1`
128 |
129 | ```javascript
130 | var promise = new Promise((resolve, reject) => {
131 | setTimeout(function () {
132 | resolve('test simplePromise resolve')
133 | }, 100)
134 | })
135 | promise.then(function (value) {
136 | console.log('success:', value)
137 | }, function (reason) {
138 | console.log('failed:', reason)
139 | })
140 | ```
141 |
142 | 你会发现,什么反应都没有。从这里可以看出,它还不能处理异步的情况。
143 |
144 | 不能处理异步,那就不能称为Promise。要支持异步,then方法里面的参数就不能立即执行。既然不能立即执行,那就必须找地方先保存起来!
145 |
146 | ### 支持异步
147 |
148 | 在Promise构造函数中添加两个回调数组
149 |
150 | ```javascript
151 | _this.onFulfilledCallbacks = []
152 | _this.onRejectedCallbacks = []
153 | ```
154 |
155 | 在then方法中添加
156 |
157 | ```javascript
158 | if (_this.status == 'pending') {
159 | _this.onFulfilledCallbacks.push(function () {
160 | onFulfilled(_this.value)
161 | })
162 | _this.onRejectedCallbacks.push(function () {
163 | onRejected(_this.reason)
164 | })
165 | }
166 | ```
167 |
168 | 在resolve和reject中调用
169 |
170 | ```javascript
171 | function resolve(value) {
172 | if (_this.status === 'pending') {
173 | _this.status = 'fulfilled'
174 | _this.value = value
175 | _this.onFulfilledCallbacks.forEach(function (fn) {
176 | fn()
177 | })
178 | }
179 | }
180 |
181 | function reject(reason) {
182 | if (_this.status === 'pending') {
183 | _this.status = 'rejected'
184 | _this.reason = reason
185 | _this.onRejectedCallbacks.forEach(function (fn) {
186 | fn()
187 | })
188 | }
189 | }
190 | ```
191 |
192 | 再用`Q1`测试,就没有问题了。
193 |
194 | 下面来用`Q2`测试一下
195 |
196 | ```javascript
197 | var promise = new Promise((resolve, reject) => {
198 | resolve('test simplePromise fulfilled')
199 | })
200 | promise.then(function (value) {
201 | console.log('success:', value)
202 | }, function (reason) {
203 | console.log('failed:', reason)
204 | }).then(function (value) {
205 | console.log('success:', value)
206 | }, function (reason) {
207 | console.log('failed:', reason)
208 | })
209 | ```
210 |
211 | 结果是:`TypeError: Cannot read property 'then' of undefined`。这个结果表明,目前的Promise还不能解决链式调用的问题。
212 |
213 | ### 链式调用
214 |
215 | 要实现链式调用的功能,首先想到是then方法返回this。如果返回this的话,会有什么问题呢?
216 |
217 | 想象一下,经过第一个then方法之后,Promise的状态改变了,而状态改变一次就不能更改了,继续使用`this.then`,那它传入的`onFulfilled`,` onRejected`都无法执行,后面链式调用再多的then都不会执行。所以这条路行不通。
218 |
219 | 所以我们只有通过返回一个新的promise,为什么呢?因为新的Promise有then方法,可以实现链式调用。
220 |
221 | 继续对Promise的then进行改造
222 |
223 | ```javascript
224 | let newPromise
225 | if (_this.status == 'fulfilled') {
226 | newPromise = new Promise(function(resolve,reject){
227 | let x = onFulfilled(_this.value)
228 | resolve(x)
229 | })
230 | }
231 |
232 | if (_this.status == 'rejected') {
233 | newPromise = new Promise(function(resolve,reject){
234 | let x = onRejected(_this.reason)
235 | resolve(x)
236 | })
237 | }
238 |
239 | if (_this.status == 'pending'){
240 | newPromise = new Promise(function(resolve,reject){
241 | _this.onFulfilledCallbacks.push(function(){
242 | let x = onFulfilled(_this.value)
243 | resolve(x)
244 | })
245 |
246 | _this.onRejectedCallbacks.push(function(){
247 | let x = onRejected(_this.reason)
248 | resolve(x)
249 | })
250 | })
251 | }
252 | return newPromise
253 | ```
254 |
255 | > 这里需要解释一下:newPromise的状态不能因为上一个promise被reject了,也reject;也就是说上一个promise无论被 reject 还是被 resolve , newPromise 都会被 resolve,只有newPromise出现异常时才会被 reject。
256 |
257 | 再用`Q2`测试一下,发现链式调用的问题就解决了。
258 |
259 | 再来看下 `Q3`
260 |
261 | ```javascript
262 | let promise = new Promise((resolve,reject) => {
263 | throw new Error('error')
264 | })
265 | promise.then((value)=>{
266 | console.log('success:',value)
267 | },(reason)=>{
268 | console.log('reject:',reason)
269 | })
270 | ```
271 |
272 | 结果:`Error: error…`,报了一堆错误。也就是说现在的Promise还不够健壮,还没有错误处理机制,在发生错误的时候,手足无措,不知道到底该`resove`还是`reject`。
273 |
274 | ### 异常处理
275 |
276 | 构造函数中
277 |
278 | ```javascript
279 | if (!(this instanceof Promise)) {
280 | return new Promise(executor);
281 | }
282 |
283 | if (typeof executor !== 'function') {
284 | throw new TypeError('Promise executor is not a function');
285 | }
286 |
287 | try{
288 | executor(function (value) {
289 | resolve(value)
290 | }, function (reason) {
291 | reject(reason)
292 | })
293 | }catch(e){
294 | reject(e)
295 | }
296 | ```
297 |
298 | then方法中
299 |
300 | ```javascript
301 | if (_this.status == 'fulfilled') {
302 | newPromise = new Promise(function(resolve,reject){
303 | try{
304 | let x = onFulfilled(_this.value)
305 | resolve(x)
306 | }catch(e){
307 | reject(e)
308 | }
309 | })
310 | }
311 |
312 | if (_this.status == 'rejected') {
313 | newPromise = new Promise(function(resolve,reject){
314 | try{
315 | let x = onRejected(_this.reason)
316 | resolve(x)
317 | }catch(e){
318 | reject(e)
319 | }
320 |
321 | })
322 | }
323 |
324 | if (_this.status == 'pending'){
325 | newPromise = new Promise(function(resolve,reject){
326 | _this.onFulfilledCallbacks.push(function(){
327 | try{
328 | let x = onFulfilled(_this.value)
329 | resolve(x)
330 | }catch(e){
331 | reject(e)
332 | }
333 | })
334 | _this.onRejectedCallbacks.push(function(){ //add
335 | try{
336 | let x = onRejected(_this.reason)
337 | resolve(x)
338 | }catch(e){
339 | reject(e)
340 | }
341 | })
342 |
343 | })
344 | }
345 | ```
346 |
347 | 再来看上面`Q3`的结果:`reject: Error: error`,程序并不会崩溃。
348 |
349 | 再来看下`Q4`
350 |
351 | ```javascript
352 | new Promise((resolve,reject)=>{
353 | resolve(1)
354 | }).then().then().then((value)=>{
355 | console.log('resolve',value)
356 | },(reason)=>{
357 | console.log('reject',reason)
358 | })
359 | ```
360 |
361 | 结果:`reject TypeError: onRejected is not a function`,不应该打印`resolve 1`?按照原生的Promise,不是应该往下传递`1`吗?`1`哪里去了,毫无疑问,丢了!丢了,那我们就想办法把它找回来。
362 |
363 | ### 值穿透
364 |
365 | 先来解释一下为什么:第一个then里面没有传参,导致` onFulfilled`就取不到,下面的代码
366 |
367 | ```javascript
368 | if (_this.status == 'fulfilled') {
369 | newPromise = new Promise(function(resolve,reject){
370 | try{
371 | let x = onFulfilled(_this.value)
372 | resolve(x)
373 | }catch(e){
374 | reject(e)
375 | }
376 | })
377 | }
378 | ```
379 |
380 | 中的` let x = onFulfilled(_this.value)`就会报错,会被捕获,然后`reject(e)`,第二个then里面同样没有传参
381 |
382 | ```javascript
383 | if (_this.status == 'rejected') {
384 | newPromise = new Promise(function(resolve,reject){
385 | try{
386 | let x = onRejected(_this.reason)
387 | resolve(x)
388 | }catch(e){
389 | reject(e)
390 | }
391 | })
392 | }
393 | ```
394 |
395 | `onRejected`也获取不到,同样`reject(e)`。传到最后一个,`reject TypeError: onRejected is not a function`。毫无疑问,当初`resolve`的`1`丢了。
396 |
397 | 我们可不可以这样:当你在`then`不传参数的时候,我们就给`onFulfilled`和`onRejected`默认一个方法,最起码不会造成`onFulfilled`和`onRejected`找不到的情况。既然默认一个方法了,实现值穿透就好办了,让它只做一件事情:给它传什么参数,它就返回什么参数。
398 |
399 | 我们可以在then方法中添加
400 |
401 | ```javascript
402 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
403 | return value
404 | }
405 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
406 | throw err
407 | }
408 | ```
409 |
410 | 再来试验下`Q4`,结果就是`resolve 1`了。
411 |
412 | 回头看下,我们已经在这个`Promise`的雏形上打了不少补丁了:`异步调用`,`链式调用` ,`异常处理`,`值穿透`。但是这还远远不够,比如,下面的情况又没办法解决了。
413 |
414 | `Q5`
415 |
416 | ```javascript
417 | var promise = new Promise((resolve,reject) => {
418 | setTimeout(function(){
419 | resolve('test simplePromise resolve')
420 | },100)
421 | })
422 |
423 | setTimeout(() => {
424 | promise.then(function(value){
425 | console.log('success:',value)
426 | },function(reason){
427 | console.log('failed:',reason)
428 | })
429 | console.log('end')
430 | }, 200);
431 | ```
432 |
433 | 结果:
434 |
435 | ```javascript
436 | success: test simplePromise resolve
437 | end
438 | ```
439 |
440 | 是不是感觉哪里不对劲?从上面可以分析出,then方法中的传入的`onFulfilled`和`onRejected`方法执行时机不正确,他应该在`console.log('end')`之后执行,也就是说它应该是异步执行。这一点也正是规范`2.2.4`规定的。`setTimeout`可以模拟异步执行,先用`setTimeout`改造一下试试。
441 |
442 | ### 异步调用then回调函数
443 |
444 | then方法中
445 |
446 | ```javascript
447 | newPromise = new Promise(function(resolve,reject){
448 | setTimeout(function () {
449 | try{
450 | let x = onFulfilled(_this.value)
451 | resolve(x)
452 | }catch(e){
453 | reject(e)
454 | }
455 | })
456 | })
457 |
458 | newPromise = new Promise(function(resolve,reject){
459 | setTimeout(function () {
460 | try{
461 | let x = onRejected(_this.reason)
462 | resolve(x)
463 | }catch(e){
464 | reject(e)
465 | }
466 | })
467 | })
468 |
469 | newPromise = new Promise(function(resolve,reject){
470 | _this.onResolvedCallbacks.push(function(){
471 | setTimeout(function () {
472 | try {
473 | let x = onFulfilled(_this.value)
474 | resolve(x)
475 | } catch (e) {
476 | reject(e)
477 | }
478 | })
479 | })
480 | _this.onRejectedCallbacks.push(function(){
481 | setTimeout(function () {
482 | try {
483 | let x = onFulfilled(_this.value)
484 | resolve(x)
485 | } catch (e) {
486 | reject(e)
487 | }
488 | })
489 | })
490 |
491 | })
492 | ```
493 |
494 | 验证`Q5`发现,打印出的结果是符合我们预期的。
495 |
496 | ```javascript
497 | end
498 | success: test simplePromise resolve
499 | ```
500 |
501 | 那是不是说我们这样改造一下就结束了呢?再来看下`Q6`
502 |
503 | ```javascript
504 | setTimeout(()=>{
505 | console.log(5)
506 | })
507 | new Promise((resolve,reject)=>{
508 | console.log(1)
509 | resolve(3)
510 | Promise.resolve(4).then((value)=>{
511 | console.log(value)
512 | })
513 | }).then((value)=>{
514 | console.log(value)
515 | })
516 | console.log(2)
517 | ```
518 |
519 | 结果:`1,2,5,4,3`。
520 |
521 | 用原生的验证下,发现结果是`1,2,4,3,5`,原生的结果不一致!
522 |
523 | 要想弄清楚这是怎么回事,这要从`JS`的执行机制娓娓道来!
524 |
525 | ### JS的执行机制
526 |
527 | 上图说话:
528 |
529 | 
530 |
531 | 从上图中可以看出,`JS`的事件循环是先执行宏任务,再执行微任务。每一次执行一个宏任务,都去查看微任务队列,如果有微任务,就执行所有的微任务队列。
532 |
533 | 宏任务和微任务的分类如下:
534 |
535 | - **macro-task:** `script(整体代码)`, `setTimeout`, `setInterval`, `setImmediate`, `I/O`,` UI rendering`
536 | - **micro-task:** `process.nextTick`, `Promise(原生 Promise)`, `Object.observe`, `MutationObserver`
537 |
538 | 根据这个分类,`Q6`代码的执行过程可以表示为下图
539 |
540 | 
541 |
542 | 整个流程如下:先执行宏任务中的主体代码,遇到`setTimeout`,它属于宏任务,放到宏任务队列里面,然后执行Promise构造函数,打印`1`。Promise是个微任务,首先会把其内部Promise的`console.log(4)`放到微任务队列中,然后将其本身的微任务`console.log(3)`放到微任务队列里面。继续执行主体代码打印`2`。当前宏任务执行完毕,执行微任务队列,打印`4`,`3`。微任务队列为空,继续执行宏任务,打印`5`,整个流程结束,结果`12435`。
543 |
544 | 梳理完上面的流程,我们发现使用setTimeout宏任务来异步执行then回调方法是不合适的,应该把`setTimeout`替换成微任务方法,比如`process.nextTick`(推荐使用**immediate**这个库),你可以去验证下,结果肯定是`12435`了。浏览器环境可以使用`MutationObserver`。我封装了下`asyncCall`
545 |
546 | ```javascript
547 | var asyncCall = (process && process.nextTick) || setImmediate || function (callback) {
548 | if (typeof callback !== 'function')
549 | throw new TypeError('callback is not a function');
550 | var Mutation = window.MutationObserver || window.WebKitMutationObserver;
551 | var observer = new Mutation(callback);
552 | var element = document.createTextNode('');
553 | observer.observe(element, {
554 | characterData: true
555 | });
556 | element.data = 1;
557 | } || function (callback) {
558 | if (typeof callback !== 'function')
559 | throw new TypeError('callback is not a function');
560 | setTimeout(callback, 0);
561 | };
562 | ```
563 |
564 | 这里简单起见,先用`process.nextTick`代替`setTimeout`,优化下代码。到此为止,我们写的`promise`才是真正的异步调用`then`回调函数。
565 |
566 | 继续来看下一个问题,`Q7`
567 |
568 | ```javascript
569 | new Promise((resolve, reject) => {
570 | resolve(new Promise((resolve) => {
571 | resolve(1)
572 | }))
573 | }).then((value) => {
574 | console.log('success:', value)
575 | }, (reason) => {
576 | console.log('failed:', reason)
577 | })
578 | ```
579 |
580 | 结果:
581 |
582 | ```javascript
583 | success: Promise {
584 | status: 'resolved',
585 | value: 1,
586 | reason: null,
587 | onRejectedCallbacks: [],
588 | onResolvedCallbacks: [] }
589 | ```
590 |
591 | 使用原生的Promise运行,结果是
592 |
593 | ```
594 | success: 1
595 | ```
596 |
597 | 也就是说,`resolve`目前只能处理普通值(普通值就是除`promise`对象和`thenable`对象以外的基本数据类型)的参数。如果是一个`promise`对象,我们无法正确处理,也就是对传入进来的`resolve` 的参数没有进行任何处理。
598 |
599 | 不只是`promise`的对象无法处理,对于下面的参数,当前的`promise`雏形一样无法处理:
600 |
601 | 1. 当前`promise`
602 | 2. thenable对象(长的很像`promise`的对象,具有`then`方法)
603 |
604 | ```javascript
605 | new Promise((resolve, reject) => {
606 | resolve({
607 | then: (resolve,reject)=>{
608 | resolve(1)
609 | }
610 | })
611 | }).then((value) => {
612 | console.log('success:', value)
613 | }, (reason) => {
614 | console.log('failed:', reason)
615 | })
616 | ```
617 |
618 | 3. 一调用就出错的thenable
619 |
620 | ```javascript
621 | let promise = {}
622 | Object.defineProperty(promise,'then',{
623 | value: function(){
624 | throw new Error('出错了吧')
625 | }
626 | })
627 | ```
628 |
629 | 4. 调用了resolve,又调用了reject
630 |
631 | ```javascript
632 | new Promise((resolve, reject) => {
633 | resolve(new Promise((resolve) => {
634 | resolve(1)
635 | }))
636 | reject('error')
637 | }).then((value) => {
638 | console.log('success:', value)
639 | }, (reason) => {
640 | console.log('failed:', reason)
641 | })
642 | ```
643 |
644 | 等等。
645 |
646 | 要兼容这些类型,还得先理解下上面总结的第四个核心点
647 |
648 | > 4.Promise中必须包含一个resolve方法,能够接受各种类型的值,将其处理成普通值fulfilled或者直接rejected
649 |
650 | 其实这些规范都考虑到了。下面我们按照规范2.3,一点点的写出一个复合规范的`resolve`。
651 |
652 | ### resolvePromise
653 |
654 | 首先改造`Promise`构造函数中的`resolve`,将原来的`resolve`改成`fulfill`方法。
655 |
656 | ```javascript
657 | function resolve(value) {
658 | resolvePromise(_this,value,fulfill,reject)
659 | }
660 |
661 | function fulfill(value){ //只接受普通值,不接受promise和thenable
662 | if (_this.status === 'pending') {
663 | _this.status = 'fulfilled'
664 | _this.value = value
665 | _this.onResolvedCallbacks.forEach(function (fn) {
666 | fn()
667 | })
668 | }
669 | }
670 | ```
671 |
672 | 现在你应该能明白上面提到的`fulfill`和`resolve`不是一个概念了吧!
673 |
674 | > fulfill只是一个Promise状态改变器。状态改变后,使用传进来的普通值,调用回调数组里面的回调函数。
675 | >
676 | > resolve是将传进来的数据,处理成一个普通值,并根据处理的情况,决定调用`fulfill`还是`reject`来改变状态。
677 |
678 | 根据规范来完善resolvePromise:
679 |
680 | ```javascript
681 | function resolvePromise(promise,x,fulfill,reject) {
682 |
683 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
684 | return reject(new TypeError('循环引用了'))
685 | }
686 |
687 | //2.3.2 x如果是一个promise
688 | if (x instanceof Promise) {
689 | //2.3.2.1
690 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
691 | x.then(function(y) {
692 | resolvePromise(promise, y, fulfill, reject)
693 | },reject)
694 | } else {
695 | //2.3.2.2 , 2.3.2.3
696 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么
697 | x.then(fulfill, reject)
698 | }
699 | return;
700 | }
701 | fulfill(x)
702 | }
703 | ```
704 |
705 | 先写到这里,验证下`Q7`,发现结果是正确:`success: 1`。
706 |
707 | 再来折腾下,用现在的promise来执行另一个问题:`Q8`
708 |
709 | ```javascript
710 | const B = new Promise((resolve) => {
711 | resolve(1)
712 | })
713 | const A = new Promise((resolve, reject) => {
714 | resolve(B)
715 | reject('error')
716 | })
717 | A.then((value) => {
718 | console.log('success:', value)
719 | }, (reason) => {
720 | console.log('failed:', reason)
721 | })
722 | ```
723 |
724 | 结果是:`failed:error`。
725 |
726 | 根据总结的第一点
727 |
728 | > Promise是一个状态机,有三种状态`pending`,`fulfilled`,`rejected`。只能从`pending`状态,转换为`fulfilled`或者`rejected`,不可逆转且无第三种状态转换方式
729 |
730 | 这是不正确的,也就是说我们写的Promise状态控制有问题。
731 |
732 | 先来看下为什么会有问题:根据上面的resolvePromise处理逻辑,A的resolve接收的参数是一个promise B,会去递归调用B的`then`方法。将B的then中的onFulfilled放到微任务队列中。继续执行A中的`reject('error')`,A的状态从pending更新为reject。执行A的then方法,将onRejected方法放到微任务对列中。当前微任务中包含了两个任务,一个是B的then方法中onFulfilled,一个是A的then方法中的onRejected。B的then方法中onFulfilled会去调用A的fulfill方法,但是A的状态已经改变了,无法执行fulfill的操作。执行下一个微任务A的onRejected,打印了`failed:error`。
733 |
734 | 从这个问题可以看出,我们写的promise,resolve和reject的调用并不阻塞promise状态的更新。
735 |
736 | 标准只规定了,状态改变一次就不能改变了,并没有规定resolve和reject的调用,要阻塞状态更新。虽然并没有这么硬性规定,但是大家都是这么理解的,比如你可以运行浏览器中、node中promise以及第三方bluebird,Q,lie库等,都是resolve,reject调用的时候,会阻塞promise状态更新。也就是说在调用了resolve以后,promise的状态不能被再次调用reject的时候改变直到resolve的过程结束。调用reject再调用resolve也是一样的。这也符合常理,不能调用了resolve,再去调用reject,就乱套了 。
737 |
738 | #### Promise状态阻塞更新
739 |
740 | 我们可以通过在Promise的构造函数中添加called变量的方式,来阻塞状态更新。
741 |
742 | ```javascript
743 | try {
744 | let called = false
745 | executor(function (value) {
746 | if(called) return
747 | called = true
748 | resolve(value)
749 | }, function (reason) {
750 | if(called) return
751 | called = true
752 | reject(reason)
753 | })
754 | } catch (e) {
755 | console.log(e)
756 | reject(e)
757 | }
758 | ```
759 |
760 | 再次运行`Q8`,结果:`success:1`。
761 |
762 | 继续完善`resolvePromise`,来处理下`thenable`的情况
763 |
764 | #### Handle thenable
765 |
766 | ```javascript
767 | function resolvePromise(promise,x,fulfill,reject) {
768 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
769 | return reject(new TypeError('循环引用了'))
770 | }
771 | //2.3.2 x如果是一个promise
772 | if (x instanceof Promise) {
773 | //2.3.2.1
774 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
775 | x.then(function(y) {
776 | resolvePromise(promise, y, fulfill, reject)
777 | },reject)
778 | } else {
779 | //2.3.2.2 , 2.3.2.3
780 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
781 | x.then(fulfill, reject)
782 | }
783 | return;
784 | }
785 | let called = false;
786 | //2.3.3
787 | //x 是一个thenable
788 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
789 | try {
790 | //2.3.3.1
791 | let then = x.then;
792 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
793 | then.call(x,(y)=>{
794 | if (called) return
795 | called = true
796 | resolvePromise(promise,y,fulfill,reject)
797 | },(err)=>{
798 | if (called) return
799 | called = true
800 | reject(err)
801 | })
802 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
803 | fulfill(x)
804 | }
805 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
806 | if (called) return
807 | called = true;
808 | reject(e);
809 | }
810 | }else{//2.3.3.4,x是一个普通值
811 | fulfill(x)
812 | }
813 | }
814 | ```
815 |
816 | 上面的注释已经很详细了,包括了规范规定的所有异常处理。
817 |
818 | 这里有个疑点需要重点解释一下,我们看到上述代码中出现
819 |
820 | ```javascript
821 | if (called) return
822 | called = true
823 | ```
824 |
825 | called变量是干嘛的?我们不是在Promise构造函数中刚加了这个变量吗?这里的变量和我们刚才添加的有什么不一样呢?
826 |
827 | 这个要通过下面的例子来进行解释
828 |
829 | ```javascript
830 | new Promise((resolve,reject)=>{
831 | resolve({
832 | then:(onFulfilled,onRejected)=>{
833 | onFulfilled(new Promise((resolve1)=>{
834 | setTimeout(()=>{
835 | resolve1(456)
836 | },1000)
837 | }))
838 | onRejected(789)
839 | }
840 | })
841 | }).then((value)=>{
842 | console.log('success:',value)
843 | },(reason)=>{
844 | console.log('reject:',reason)
845 | })
846 | ```
847 |
848 | 其实上面代码就类似于
849 |
850 | ```javascript
851 | new Promise((resolve,reject)=>{
852 | resolve(new Promise((resolve,reject)=>{
853 | resolve(new Promise((resolve1)=>{
854 | setTimeout(()=>{
855 | resolve1(456)
856 | },1000)
857 | }))
858 | reject(789)
859 | })
860 | }).then((value)=>{
861 | console.log('success:',value)
862 | },(reason)=>{
863 | console.log('reject:',reason)
864 | })
865 | ```
866 |
867 | 我们通过上面的代码中可以看出,`thenable`其实就是一个没有状态阻塞更新机制的`promise`。这里的called就相当于是为了防止调用了resolve又调用了reject的情况下Promise状态更新乱套的问题。
868 |
869 | ## 完整代码
870 |
871 | ```javascript
872 | function Promise(executor) {
873 | if (!(this instanceof Promise)) {
874 | return new Promise(executor);
875 | }
876 |
877 | if (typeof executor !== 'function') {
878 | throw new TypeError('Promise executor is not a function');
879 | }
880 |
881 | let _this = this
882 | _this.status = 'pending'
883 | _this.value = null
884 | _this.reason = null
885 | _this.onRejectedCallbacks = []
886 | _this.onResolvedCallbacks = []
887 |
888 | function resolve(value) {
889 | resolvePromise(_this,value,fulfill,reject)
890 | }
891 |
892 | function fulfill(value){ //只接收普通值
893 | if (_this.status === 'pending') {
894 | _this.status = 'fulfilled'
895 | _this.value = value
896 | _this.onResolvedCallbacks.forEach(function (fn) {
897 | fn()
898 | })
899 | }
900 | }
901 |
902 | function reject(reason) {
903 | if (_this.status === 'pending') {
904 | _this.status = 'rejected'
905 | _this.reason = reason
906 | _this.onRejectedCallbacks.forEach(function (fn) {
907 | fn()
908 | })
909 | }
910 | }
911 |
912 | try {
913 | let called = false
914 | executor(function (value) {
915 | if(called) return
916 | called = true
917 | resolve(value)
918 | }, function (reason) {
919 | if(called) return
920 | called = true
921 | reject(reason)
922 | })
923 | } catch (e) {
924 | reject(e)
925 | }
926 |
927 | }
928 |
929 | function resolvePromise(promise,x,fulfill,reject) {
930 |
931 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
932 | return reject(new TypeError('循环引用了'))
933 | }
934 |
935 | //2.3.2 x如果是一个promise
936 | if (x instanceof Promise) {
937 | //2.3.2.1
938 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
939 | x.then(function(y) {
940 | resolvePromise(promise, y, fulfill, reject)
941 | },reject)
942 | } else {
943 | //2.3.2.2 , 2.3.2.3
944 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
945 | x.then(fulfill, reject)
946 | }
947 | return;
948 | }
949 | let called = false;
950 | //2.3.3
951 | //x 是一个thenable
952 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
953 | try {
954 | //2.3.3.1
955 | let then = x.then;
956 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
957 | then.call(x,(y)=>{
958 | if (called) return
959 | called = true
960 | resolvePromise(promise,y,fulfill,reject)
961 | },(err)=>{
962 | if (called) return
963 | called = true
964 | reject(err)
965 | })
966 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
967 | fulfill(x)
968 | }
969 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
970 | if (called) return
971 | called = true;
972 | reject(e);
973 | }
974 | }else{//2.3.3.4,x是一个普通值
975 | fulfill(x)
976 | }
977 | }
978 | Promise.prototype.then = function (onFulfilled, onRejected) {
979 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
980 | return value
981 | }
982 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
983 | throw err
984 | }
985 | let _this = this
986 | let newPromise
987 | if (_this.status === 'fulfilled') {
988 | newPromise = new Promise(function (resolve, reject) {
989 | process.nextTick(function () {
990 | try {
991 | let x = onFulfilled(_this.value)
992 | resolve(x)
993 | } catch (e) {
994 | reject(e)
995 | }
996 | })
997 | })
998 | }
999 |
1000 | if (_this.status === 'rejected') {
1001 | newPromise = new Promise(function (resolve, reject) {
1002 | process.nextTick(function () {
1003 | try {
1004 | let x = onRejected(_this.reason)
1005 | resolve(x)
1006 | } catch (e) {
1007 | reject(e)
1008 | }
1009 | })
1010 | })
1011 | }
1012 |
1013 | if (_this.status === 'pending') {
1014 | newPromise = new Promise(function (resolve, reject) {
1015 |
1016 | _this.onResolvedCallbacks.push(function () {
1017 | process.nextTick(function () {
1018 | try {
1019 | let x = onFulfilled(_this.value)
1020 | resolve(x)
1021 | } catch (e) {
1022 | reject(e)
1023 | }
1024 | })
1025 |
1026 | })
1027 | _this.onRejectedCallbacks.push(function () {
1028 | process.nextTick(function () {
1029 | try {
1030 | let x = onRejected(_this.reason)
1031 | resolve(x)
1032 | } catch (e) {
1033 | reject(e)
1034 | }
1035 | })
1036 | })
1037 |
1038 | })
1039 | }
1040 | return newPromise
1041 | }
1042 | module.exports = Promise
1043 | ```
1044 |
1045 |
1046 |
1047 | ## 测试
1048 |
1049 | 首先你要暴露一个接口:
1050 |
1051 | ```javascript
1052 | Promise.deferred = Promise.defer = function () {
1053 | var dfd = {}
1054 | dfd.promise = new Promise(function (resolve, reject) {
1055 | dfd.resolve = resolve
1056 | dfd.reject = reject
1057 | })
1058 | return dfd
1059 | }
1060 | ```
1061 |
1062 | 使用`promises-aplus-tests`这个库,具体使用方法,请移步它的github去查看,不详细介绍了。
1063 |
1064 | ```
1065 | npm install promises-aplus-tests
1066 | promises-aplus-tests myPromise.js
1067 | ```
1068 |
1069 | 测试通过:
1070 |
1071 | 
1072 |
1073 | ## 其他方法
1074 |
1075 | ```javascript
1076 | Promise.prototype.catch = function(callback){
1077 | return this.then(null,callback)
1078 | }
1079 | Promise.resolve = function(value){ //返回一个promise
1080 | return new Promise(function(resolve,reject){
1081 | resolve(value);
1082 | })
1083 | }
1084 | Promise.reject = function(value){//返回一个promise
1085 | return new Promise(function(resolve,reject){
1086 | reject(value);
1087 | })
1088 | }
1089 | Promise.race = function(promise){//只要有一个成功了就resolve,有一个失败了就reject
1090 | return new Promise(function (resolve,reject){
1091 | for(var i = 0;i{
11 | console.log('then:',value)
12 | }).catch((error)=>{
13 | console.log('catch:',error)
14 | })
15 | ```
16 |
17 | ```javascript
18 | new Promise((resolve, reject) => {
19 | resolve({
20 | then:(onFulfilled,onRejected)=>{
21 | onFulfilled(new Promise((resolve1)=>{
22 | setTimeout(()=>{
23 | resolve1(456)
24 | },1000)
25 | }))
26 | onRejected(789)
27 | }
28 | })
29 | }).then((value) => {
30 | console.log('fulfilled:', value)
31 | }, (reason) => {
32 | console.log('rejected:', reason)
33 | })
34 | ```
35 |
36 | 以上每个问题的答案是什么?为什么?是不是有点懵逼?你还敢说你熟悉吗?(如果你很清楚,那恭喜你,下面的你不用看了,这里已经不适合你了)
37 |
38 | 要正确解释上面的问题,你需要充分的了解JS的运行机制以及Promise的实现原理。本文的目的就是让你明白Promise到底是个什么东西。
39 |
40 | 下面,我们从一个Promise雏形开始,通过打补丁的方式,一步一步实现一个完整的Promise。Promise的原理,顺其自然就明白了!
41 |
42 | ## PromiseA+规范
43 |
44 | 首先来看下规范,[https://promisesaplus.com](https://promisesaplus.com)。是不是顿时又懵逼了,这么长,这都是啥和啥啊。。。
45 |
46 | 别怕,我简单总结了下它的核心点,也就四个:
47 |
48 | 1.Promise是一个状态机,有三种状态pending,fulfilled,rejected。只能从pending状态,转换为fulfilled或者rejected,不可逆转且无第三种状态转换方式。
49 |
50 | 2.必须提供一个then方法用以处理当前值:终值和据因。then接收两个参数onFufilled,onRejected分别处理fulfilled和reject的结果。
51 |
52 | 3.then方法必须返回一个新的Promise , 便于链式调用。
53 |
54 | 4.Promise中必须包含一个resolve方法,能够接受各种类型的值,将其处理成普通值fulfilled或者直接rejected
55 |
56 | ## Promise雏形
57 |
58 | 先来实现一个promise的雏形:
59 |
60 | ```javascript
61 | function Promise(executor) {
62 |
63 | let _this = this
64 | _this.status = 'pending'
65 | _this.value = null
66 | _this.reason = null
67 |
68 | function resolve(value) {
69 | if (_this.status === 'pending') {
70 | _this.status = 'fulfilled'
71 | _this.value = value
72 | }
73 | }
74 |
75 | function reject(reason) {
76 | if (_this.status === 'pending') {
77 | _this.status = 'rejected'
78 | _this.reason = reason
79 | }
80 | }
81 | //暂时不要问为什么写那么啰嗦,山人自有妙计,文末分解
82 | executor(function (value) {
83 | resolve(value)
84 | }, function (reason) {
85 | reject(reason)
86 | },)
87 | }
88 |
89 | Promise.prototype.then = function (onFulfilled, onRejected) {
90 | let _this = this
91 |
92 | if (_this.status == 'fulfilled') {
93 | onFulfilled(_this.value)
94 | }
95 |
96 | if (_this.status == 'rejected') {
97 | onRejected(_this.reason)
98 | }
99 | }
100 | ```
101 |
102 | 从上面的代码中,promise里面的东西是很健全的:有改变promise装态的两个方法resolve(确切的说,这个方法应该叫fulfill,fulfill和resolve是概念是不一样的,后面会解释原因)和reject,有管理状态的status,保存fulfilled状态值的value和rejected拒因的reason,还包含了一个then方法用来处理fulfilled的值和rejected的据因(还有一行`小注释`)。
103 |
104 | 试验一下效果:
105 |
106 | ```javascript
107 | var promise = new Promise((resolve, reject) => {
108 | resolve('test simplePromise resolve')
109 | })
110 |
111 | promise.then(function (value) {
112 | console.log('success:', value)
113 | }, function (reason) {
114 | console.log('failed:', reason)
115 | })
116 | ```
117 |
118 | 妥妥的`success:test simplePromise resolve`,基本什么问题,有点promise的样子。
119 |
120 | 来个问题测试一下,`Q1`
121 |
122 | ```javascript
123 | var promise = new Promise((resolve, reject) => {
124 | setTimeout(function () {
125 | resolve('test simplePromise resolve')
126 | }, 100)
127 | })
128 | promise.then(function (value) {
129 | console.log('success:', value)
130 | }, function (reason) {
131 | console.log('failed:', reason)
132 | })
133 | ```
134 |
135 | 你会发现,结果什么反应都没有。。。
136 |
137 | 从这里可以看出,它还不能处理异步的情况。不能处理异步,那叫什么Promise。要支持异步,then方法里面的参数就不能立即执行。既然不能立即执行,那就必须找地方,先保存起来!
138 |
139 | ### 支持异步
140 |
141 | 在Promise构造函数中添加两个回调数组
142 |
143 | ```javascript
144 | _this.onFulfilledCallbacks = []
145 | _this.onRejectedCallbacks = []
146 | ```
147 |
148 | 在then方法中添加
149 |
150 | ```javascript
151 | if (_this.status == 'pending') {
152 | _this.onFulfilledCallbacks.push(function () {
153 | onFulfilled(_this.value)
154 | })
155 | _this.onRejectedCallbacks.push(function () {
156 | onRejected(_this.reason)
157 | })
158 | }
159 | ```
160 |
161 | 在resolve和reject中调用
162 |
163 | ```javascript
164 | function resolve(value) {
165 | if (_this.status === 'pending') {
166 | _this.status = 'fulfilled'
167 | _this.value = value
168 | _this.onFulfilledCallbacks.forEach(function (fn) {
169 | fn()
170 | })
171 | }
172 | }
173 |
174 | function reject(reason) {
175 | if (_this.status === 'pending') {
176 | _this.status = 'rejected'
177 | _this.reason = reason
178 | _this.onRejectedCallbacks.forEach(function (fn) {
179 | fn()
180 | })
181 | }
182 | }
183 | ```
184 |
185 | 好了,这样就实现了异步调用,用`Q1`测试是没有问题的。增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_async_2.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_async_2.js)
186 |
187 | 来继续下一个话题,`Q2`
188 |
189 | ```javascript
190 | var promise = new Promise((resolve, reject) => {
191 | resolve('test simplePromise fulfilled')
192 | })
193 | promise.then(function (value) {
194 | console.log('success:', value)
195 | }, function (reason) {
196 | console.log('failed:', reason)
197 | }).then(function (value) {
198 | console.log('success:', value)
199 | }, function (reason) {
200 | console.log('failed:', reason)
201 | })
202 | ```
203 |
204 | 结果是:`TypeError: Cannot read property 'then' of undefined`,说好的链式调用呢。。。
205 |
206 | ### 链式调用
207 |
208 | 实现链式调用,首先想到就是then方法返回this。返回this有什么问题呢,你经过第一个then方法之后,你的状态改变了,那你继续使用this.then,Promise转态改变一次就不能更改了,所以它传入的参数都无法执行,后面跟再多的then都不会执行,这显然不行。所以我们只有通过返回一个新的promise,为啥呢,promise有then方法啊!!!
209 |
210 | 继续打补丁,对then方法进行改造。
211 |
212 | ```javascript
213 | let newPromise
214 | if (_this.status == 'fulfilled') {
215 | newPromise = new Promise(function(resolve,reject){
216 | let x = onFulfilled(_this.value)
217 | resolve(x)
218 | })
219 | }
220 |
221 | if (_this.status == 'rejected') {
222 | newPromise = new Promise(function(resolve,reject){
223 | let x = onRejected(_this.reason)
224 | resolve(x)
225 | })
226 | }
227 |
228 | if (_this.status == 'pending'){
229 | newPromise = new Promise(function(resolve,reject){
230 | _this.onFulfilledCallbacks.push(function(){
231 | let x = onFulfilled(_this.value)
232 | resolve(x)
233 | })
234 |
235 | _this.onRejectedCallbacks.push(function(){
236 | let x = onRejected(_this.reason)
237 | resolve(x)
238 | })
239 | })
240 | }
241 | return newPromise
242 | ```
243 |
244 | > 这里需要解释一下:newPromise的状态不能因为上一个promise被reject了,而更改newPromise的状态;也就是说上一个promise无论被 reject 还是被 resolve , newPromise 都会被 resolve,只有出现异常时才会被 rejecte。
245 |
246 | `Q2`链式调用的问题也就解决了。增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_chain_3.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_chain_3.js)。
247 |
248 | 那,抛个错误玩玩?看下 `Q3`
249 |
250 | ```javascript
251 | let promise = new Promise((resolve,reject) => {
252 | throw new Error('error')
253 | })
254 | promise.then((value)=>{
255 | console.log('success:',value)
256 | },(reason)=>{
257 | console.log('reject:',reason)
258 | })
259 | ```
260 |
261 | 结果:`Error: error.....`,一堆错误,还是太年轻,经不起一点挫折啊。。。
262 |
263 | ### 异常处理
264 |
265 | 来吧,继续打补丁,加上错误处理
266 |
267 | ```javascript
268 | if (!(this instanceof Promise)) {
269 | return new Promise(executor);
270 | }
271 |
272 | if (typeof executor !== 'function') {
273 | throw new TypeError('Promise executor is not a function');
274 | }
275 |
276 | try{
277 | executor(function (value) {
278 | resolve(value)
279 | }, function (reason) {
280 | reject(reason)
281 | })
282 | }catch(e){
283 | reject(e)
284 | }
285 | ```
286 |
287 | then方法中
288 |
289 | ```javascript
290 | if (_this.status == 'fulfilled') {
291 | newPromise = new Promise(function(resolve,reject){
292 | try{
293 | let x = onFulfilled(_this.value)
294 | resolve(x)
295 | }catch(e){
296 | reject(e)
297 | }
298 |
299 | })
300 | }
301 |
302 | if (_this.status == 'rejected') {
303 | newPromise = new Promise(function(resolve,reject){
304 | try{
305 | let x = onRejected(_this.reason)
306 | resolve(x)
307 | }catch(e){
308 | reject(e)
309 | }
310 |
311 | })
312 | }
313 |
314 | if (_this.status == 'pending'){
315 | newPromise = new Promise(function(resolve,reject){
316 | _this.onFulfilledCallbacks.push(function(){
317 | try{
318 | let x = onFulfilled(_this.value)
319 | resolve(x)
320 | }catch(e){
321 | reject(e)
322 | }
323 | })
324 | _this.onRejectedCallbacks.push(function(){ //add
325 | try{
326 | let x = onRejected(_this.reason)
327 | resolve(x)
328 | }catch(e){
329 | reject(e)
330 | }
331 | })
332 |
333 | })
334 | }
335 | ```
336 |
337 | 再来看上面的结果:`reject: Error: error`,程序并不会崩溃,处理异常就是这么淡定!增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_withCatchError_4.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_withCatchError_4.js)
338 |
339 | > 人生从来都不是一帆风顺的,有一个坑,就会有更多坑!
340 |
341 | 比如下面的问题跑个试试,`Q4`
342 |
343 | ```javascript
344 | new Promise((resolve,reject)=>{
345 | resolve(1)
346 | }).then().then().then((value)=>{
347 | console.log(value)
348 | },(reason)=>{console.log(reason)})
349 | ```
350 |
351 | 结果:`TypeError: onRejected is not a function`,怎么又变成了车祸现场了?按照原生的Promise,不是应该打印`1`吗?`1`哪里去了,毫无疑问,丢了!丢了,那就把它找回来。
352 |
353 | ### 值穿透
354 |
355 | 先来解释一下为什么:then里面啥也不传,也就是说,onFulfilled就取不到,下面的代码
356 |
357 | ```javascript
358 | newPromise = new Promise(function (resolve, reject) {
359 | process.nextTick(function () {
360 | try {
361 | let x = onFulfilled(_this.value)
362 | resolve(x)
363 | } catch (e) {
364 | reject(e)
365 | }
366 | })
367 | })
368 | ```
369 |
370 | 中的` let x = onFulfilled(_this.value)`就会报错,会被捕获,然后`reject(e)`,下一个then啥也不传,同样的结果,传到最后一个,被捕获了。
371 |
372 | 毫无疑问`1`丢了,我们可不可以这样:既然你不传,我们就给你默认一个方法,这样不至于造成车祸现场。我们还想值穿透怎么办?使这个方法啥也不干,就只干一件事,给它啥,它吐出来啥!
373 |
374 | 在then方法中,添加
375 |
376 | ```javascript
377 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
378 | return value
379 | }
380 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
381 | throw err
382 | }
383 | ```
384 |
385 | 搞定!增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_transmit_value_5.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_transmit_value_5.js)
386 |
387 | 我们解决了不少问题了:`异步调用`,`链式调用` ,`异常处理`,`值穿透`,是不是可以休息会了?当然不行!
388 |
389 | > 人生本来就不太平,就是一个接一个的坎!
390 |
391 | 比如,下面的情况又没办法解决了。。。
392 |
393 | `Q5`
394 |
395 | ```javascript
396 | var promise = new Promise((resolve,reject) => {
397 | setTimeout(function(){
398 | resolve('test simplePromise resolve')
399 | },100)
400 | })
401 |
402 | setTimeout(() => {
403 | promise.then(function(value){
404 | console.log('success:',value)
405 | },function(reason){
406 | console.log('failed:',reason)
407 | })
408 | console.log('end')
409 | }, 200);
410 | ```
411 |
412 | 结果:
413 |
414 | ```javascript
415 | success: test simplePromise resolve
416 | end
417 | ```
418 |
419 | 是不是感觉哪里不对劲?是的,为什么`end`会在`success`之后打印?Promise不就是来解决异步的吗?
420 |
421 | 从上面可以分析出,then方法中的传入的onFulfilled和onRejected方法执行时机不正确。它应该是异步执行。这一点也正是规范2.2.4规定的,不清楚的可以看下规范。
422 |
423 | 那既然异步执行,那就再套一层马甲呗,setTimeout不就可以模拟异步执行嘛,那就用setTimeout改造一下试试。
424 |
425 | ### 异步调用then回调函数
426 |
427 | ```javascript
428 | newPromise = new Promise(function(resolve,reject){
429 | setTimeout(function () {
430 | try{
431 | let x = onFulfilled(_this.value)
432 | resolve(x)
433 | }catch(e){
434 | reject(e)
435 | }
436 | })
437 |
438 | })
439 |
440 | newPromise = new Promise(function(resolve,reject){
441 | setTimeout(function () {
442 | try{
443 | let x = onRejected(_this.reason)
444 | resolve(x)
445 | }catch(e){
446 | reject(e)
447 | }
448 | })
449 |
450 | })
451 |
452 | newPromise = new Promise(function(resolve,reject){
453 | _this.onResolvedCallbacks.push(function(){
454 | setTimeout(function () {
455 | try {
456 | let x = onFulfilled(_this.value)
457 | resolve(x)
458 | } catch (e) {
459 | reject(e)
460 | }
461 | })
462 | })
463 | _this.onRejectedCallbacks.push(function(){
464 | setTimeout(function () {
465 | try {
466 | let x = onFulfilled(_this.value)
467 | resolve(x)
468 | } catch (e) {
469 | reject(e)
470 | }
471 | })
472 | })
473 |
474 | })
475 | ```
476 |
477 | 验证`Q5`发现,打印出的结果是符合我们预期的。增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_async_then_6.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_async_then_6.js)。那再验证下其他的异步情况
478 |
479 | `Q6`
480 |
481 | ```javascript
482 | setTimeout(()=>{
483 | console.log(5)
484 | })
485 | new Promise((resolve,reject)=>{
486 | console.log(1)
487 | resolve(3)
488 | Promise.resolve(4).then((value)=>{
489 | console.log(value)
490 | })
491 | }).then((value)=>{
492 | console.log(value)
493 | })
494 | console.log(2)
495 | ```
496 |
497 | 结果:`1,2,5,4,3`。
498 |
499 | 用原生的验证下,发现结果是`1,2,4,3,5`,那我们的为什么和原生的结果不一样呢?这要从JS的执行机制娓娓道来!
500 |
501 | 上图说话:
502 |
503 | 
504 |
505 | 从上图中可以看出,js的事件循环是先执行宏任务,再执行微任务。每一次执行一个宏任务,都去查看微任务队列,如果有微任务,就执行所有的微任务队列。(这里不细说,详细可参考:[https://juejin.im/post/59e85eebf265da430d571f89](https://juejin.im/post/59e85eebf265da430d571f89))
506 |
507 | 宏任务和微任务的分类如下:
508 |
509 | - **macro-task:** script(整体代码), `setTimeout`, `setInterval`, `setImmediate`, I/O, UI rendering
510 | - **micro-task:** `process.nextTick`, `Promise`(原生 Promise),`Object.observe`, `MutationObserver`
511 |
512 | 根据这个分类,`Q6`的执行过程可以表示为
513 |
514 | 
515 |
516 | 整个流程如下:先执行宏任务中的整体代码,遇到setTimeout,它属于宏任务,放到宏任务队列里面,然后执行Promise构造函数,打印1。Promise是个微任务,会把构造函数内部Promise的`console.log(4)`放到微任务中,然后外面Promise中的`console.log(3)`。继续执行打印2。当前宏任务执行完毕,执行微任务队列,打印4,3。微任务队列为空,继续执行宏任务,打印5,整个流程结束,结果`12435`。
517 |
518 | 梳理完上面的流程,再看我们的代码就能明白,使用setTimeout宏任务来异步执行then回调方法是不太合适的,应该把setTimeout替换成微任务方法(推荐使用**immediate**这个库),比如process.nextTick,你可以去验证下,结果肯定是`12435`了。浏览器环境可以使用`MutationObserver`。我封装了下asyncCall
519 |
520 | ```javascript
521 | var asyncCall = (process && process.nextTick) || setImmediate || function (callback) {
522 | if (typeof callback !== 'function')
523 | throw new TypeError('callback is not a function');
524 | var Mutation = window.MutationObserver || window.WebKitMutationObserver;
525 | var observer = new Mutation(callback);
526 | var element = document.createTextNode('');
527 | observer.observe(element, {
528 | characterData: true
529 | });
530 | element.data = 1;
531 | } || function (callback) {
532 | if (typeof callback !== 'function')
533 | throw new TypeError('callback is not a function');
534 | setTimeout(callback, 0);
535 | };
536 | ```
537 |
538 | 这里简单起见,就先用process.nextTick来改造。增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_nextTick_7.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_nextTick_7.js)
539 |
540 | 下面来看下一个问题:
541 |
542 | `Q7`
543 |
544 | ```javascript
545 | new Promise((resolve, reject) => {
546 | resolve(new Promise((resolve) => {
547 | resolve(1)
548 | }))
549 | }).then((value) => {
550 | console.log('success:', value)
551 | }, (reason) => {
552 | console.log('failed:', reason)
553 | })
554 | ```
555 |
556 | 结果:
557 |
558 | ```javascript
559 | success: Promise {
560 | status: 'resolved',
561 | value: 1,
562 | reason: null,
563 | onRejectedCallbacks: [],
564 | onResolvedCallbacks: [] }
565 | ```
566 |
567 | 使用原生的Promise运行,结果是
568 |
569 | ```
570 | success: 1
571 | ```
572 |
573 | 我们无法正确处理,写的不符合规范,也就是对传入进来的值没有进行任何处理。对于下面的异常情况,我们一样无法处理:
574 |
575 | 1. 传进来的是当前promise
576 | 2. thenable
577 |
578 | ```javascript
579 | new Promise((resolve, reject) => {
580 | resolve({
581 | then: (resolve,reject)=>{
582 | resolve(1)
583 | }
584 | })
585 | }).then((value) => {
586 | console.log('success:', value)
587 | }, (reason) => {
588 | console.log('failed:', reason)
589 | })
590 | ```
591 |
592 | 3. 或者一调用就出错的thenable
593 |
594 | ```javascript
595 | let promise = {}
596 | Object.defineProperty(promise,'then',{
597 | value: function(){
598 | throw new Error('出错了吧')
599 | }
600 | })
601 | ```
602 |
603 | 4. 调用了resolve,又调用了reject
604 |
605 | ```javascript
606 | new Promise((resolve, reject) => {
607 | resolve(new Promise((resolve) => {
608 | resolve(1)
609 | }))
610 | reject('error')
611 | }).then((value) => {
612 | console.log('success:', value)
613 | }, (reason) => {
614 | console.log('failed:', reason)
615 | })
616 | ```
617 |
618 | 等等。
619 |
620 | 其实这些规范都考虑到了。
621 |
622 | 要解决这个问题,还得先理解下上面我们总结的第四个核心点
623 |
624 | > 4.Promise中必须包含一个resolve方法,能够接受各种类型的值,将其处理成普通值fulfilled或者直接rejected
625 |
626 | 这也是规范里面2.3规定的。下面我们来一点点的按照规范,写出一个复合规范的resolve。
627 |
628 | ### resolvePromise
629 |
630 | 首先改造Promise构造函数中的resolve
631 |
632 | ```javascript
633 | function resolve(value) {
634 | resolvePromise(_this,value,fulfill,reject)
635 | }
636 |
637 | function fulfill(value){ //只接受普通值,不接受promise和thenable
638 | if (_this.status === 'pending') {
639 | _this.status = 'resolved'
640 | _this.value = value
641 | _this.onResolvedCallbacks.forEach(function (fn) {
642 | fn()
643 | })
644 | }
645 | }
646 | ```
647 |
648 | 将原来的resolve改成fulfill方法。现在你应该能明白上面提到的fulfill和resolve不是一个概念了吧!
649 |
650 | > fulfill只是一个状态改变器并且在改变完状态之后使用传进来的普通值,调用回调数组里面的回调函数。
651 | >
652 | > resolve是将传进来的数据,处理成一个普通值,并根据处理的情况,决定是否fulfill还是reject。
653 |
654 | 来完善resolvePromise:
655 |
656 | ```javascript
657 | function resolvePromise(promise,x,fulfill,reject) {
658 |
659 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
660 | return reject(new TypeError('循环引用了'))
661 | }
662 |
663 | //2.3.2 x如果是一个promise
664 | if (x instanceof Promise) {
665 | //2.3.2.1
666 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
667 | x.then(function(y) {
668 | resolvePromise(promise, y, fulfill, reject)
669 | },reject)
670 | } else {
671 | //2.3.2.2 , 2.3.2.3
672 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
673 | x.then(fulfill, reject)
674 | }
675 | return;
676 | }
677 | fulfill(x)
678 | }
679 | ```
680 |
681 | 我们先写到这里,验证下`Q7`,发现结果是正确的,`success: 1`。增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_without_called_8.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_without_called_8.js)
682 |
683 | 再来折腾下,用现在的promise来执行另一个问题:`Q8`
684 |
685 | ```javascript
686 | new Promise((resolve, reject) => {
687 | resolve(new Promise((resolve) => {
688 | resolve(1)
689 | }))
690 | reject('error')
691 | }).then((value) => {
692 | console.log('success:', value)
693 | }, (reason) => {
694 | console.log('failed:', reason)
695 | })
696 | ```
697 |
698 | 发现结果是:`failed:error`。为什么我们写的promise的状态不可控?
699 |
700 | 事实上是这样的,根据上面的resolvePromise,发现resolve接收的参数是一个promise,会去递归调用它的then方法,我们知道,then方法中包含微任务。然后就先执行了reject('error'),这个执行完毕,promise的状态从pending更新为reject。执行then方法,将onRejected方法放到微任务对列中。当resolve的微任务执行的时候,状态已经改变了,无法执行fulfill的操作。执行下一个微任务onRejected,打印了`failed:error`。
701 |
702 | 从这个问题可以看出,我们写的promise,resolve和reject的调用并不阻塞promise状态的更新。
703 |
704 | 标准只规定了,状态改变一次就不能改变了,并没有规定resolve和reject的调用,要阻塞状态更新。虽然并没有这么硬性规定,但是大家都是这么理解的,比如你可以运行浏览器,node原生promise以及第三方bluebird,Q,lie库等,都是resolve,reject调用的时候,会阻塞另一个方法的状态更新。这也符合常理,不能调用了resolve,再去调用reject,就乱套了 。
705 |
706 | #### Promise状态阻塞更新
707 |
708 | 我们可以通过在Promise的构造函数中添加called变量的方式,来阻塞状态更新(从这里可以看出,在文章开头加的那个注释的意思了吧)。
709 |
710 | ```javascript
711 | try {
712 | let called = false
713 | executor(function (value) {
714 | if(called) return
715 | called = true
716 | resolve(value)
717 | }, function (reason) {
718 | if(called) return
719 | called = true
720 | reject(reason)
721 | })
722 | } catch (e) {
723 | console.log(e)
724 | reject(e)
725 | }
726 | ```
727 |
728 | 再次运行`Q8`,结果:`success:1`。 增量代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_with_called_9.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_with_called_9.js)
729 |
730 | 我们继续完善`resolvePromise`,来处理下`thenable`的情况
731 |
732 | #### Handle thenable
733 |
734 | ```javascript
735 | function resolvePromise(promise,x,fulfill,reject) {
736 |
737 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
738 | return reject(new TypeError('循环引用了'))
739 | }
740 | //2.3.2 x如果是一个promise
741 | if (x instanceof Promise) {
742 | //2.3.2.1
743 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
744 | x.then(function(y) {
745 | resolvePromise(promise, y, fulfill, reject)
746 | },reject)
747 | } else {
748 | //2.3.2.2 , 2.3.2.3
749 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
750 | x.then(fulfill, reject)
751 | }
752 | return;
753 | }
754 | let called = false;
755 | //2.3.3
756 | //x 是一个thenable
757 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
758 | try {
759 | //2.3.3.1
760 | let then = x.then;
761 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
762 | then.call(x,(y)=>{
763 | if (called) return
764 | called = true
765 | resolvePromise(promise,y,fulfill,reject)
766 | },(err)=>{
767 | if (called) return
768 | called = true
769 | reject(err)
770 | })
771 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
772 | fulfill(x)
773 | }
774 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
775 | if (called) return
776 | called = true;
777 | reject(e);
778 | }
779 | }else{//2.3.3.4,x是一个普通值
780 | fulfill(x)
781 | }
782 | }
783 | ```
784 |
785 | 上面的注释已经很详细了,包括了规范规定的所有异常处理。
786 |
787 | 这里有个疑点需要重点解释一下,我们看到上述代码中出现
788 |
789 | ```javascript
790 | if (called) return
791 | called = true
792 | ```
793 |
794 | called变量是干嘛的?我们不是刚加了这个变量吗?这里的变量和我们刚才添加的有什么不一样呢?
795 |
796 | 这个要通过下面的例子来进行解释
797 |
798 | ```javascript
799 | new Promise((resolve,reject)=>{
800 | resolve({
801 | then:(onFulfilled,onRejected)=>{
802 | onFulfilled(new Promise((resolve1)=>{
803 | setTimeout(()=>{
804 | resolve1(456)
805 | },1000)
806 | }))
807 | onRejected(789)
808 | }
809 | })
810 | }).then((value)=>{
811 | console.log('success:',value)
812 | },(reason)=>{
813 | console.log('reject:',reason)
814 | })
815 | ```
816 |
817 | 其实上面代码就类似于
818 |
819 | ```javascript
820 | new Promise((resolve,reject)=>{
821 | resolve(new Promise((resolve,reject)=>{
822 | resolve(new Promise((resolve1)=>{
823 | setTimeout(()=>{
824 | resolve1(456)
825 | },1000)
826 | }))
827 | reject(789)
828 | })
829 | }).then((value)=>{
830 | console.log('success:',value)
831 | },(reason)=>{
832 | console.log('reject:',reason)
833 | })
834 | ```
835 |
836 | 我们通过上面的代码中可以看出,`thenable`其实就是一个没有状态阻塞更新机制的`promise`。这里的called就相当于是为了防止调用了resolve又调用了reject乱套的问题。
837 |
838 | ## 完整代码
839 |
840 | ```javascript
841 | function Promise(executor) {
842 | if (!(this instanceof Promise)) {
843 | return new Promise(executor);
844 | }
845 |
846 | if (typeof executor !== 'function') {
847 | throw new TypeError('Promise executor is not a function');
848 | }
849 |
850 | let _this = this
851 | _this.status = 'pending'
852 | _this.value = null
853 | _this.reason = null
854 | _this.onRejectedCallbacks = []
855 | _this.onResolvedCallbacks = []
856 |
857 | function resolve(value) {
858 | resolvePromise(_this,value,fulfill,reject)
859 | }
860 |
861 | function fulfill(value){ //只接收普通值
862 | if (_this.status === 'pending') {
863 | _this.status = 'resolved'
864 | _this.value = value
865 | _this.onResolvedCallbacks.forEach(function (fn) {
866 | fn()
867 | })
868 | }
869 | }
870 |
871 | function reject(reason) {
872 | if (_this.status === 'pending') {
873 | _this.status = 'rejected'
874 | _this.reason = reason
875 | _this.onRejectedCallbacks.forEach(function (fn) {
876 | fn()
877 | })
878 | }
879 | }
880 |
881 | try {
882 | let called = false
883 | executor(function (value) {
884 | if(called) return
885 | called = true
886 | resolve(value)
887 | }, function (reason) {
888 | if(called) return
889 | called = true
890 | reject(reason)
891 | })
892 | } catch (e) {
893 | reject(e)
894 | }
895 |
896 | }
897 |
898 | function resolvePromise(promise,x,fulfill,reject) {
899 |
900 | if (promise === x) {//2.3.1 传进来的x与当前promise相同,报错
901 | return reject(new TypeError('循环引用了'))
902 | }
903 |
904 | //2.3.2 x如果是一个promise
905 | if (x instanceof Promise) {
906 | //2.3.2.1
907 | if (x.status === 'pending') { //x状态还未改变,返回的下一个promise的resove的接收的值y不确定,对其递归处理
908 | x.then(function(y) {
909 | resolvePromise(promise, y, fulfill, reject)
910 | },reject)
911 | } else {
912 | //2.3.2.2 , 2.3.2.3
913 | //状态确定,如果fulfill那传进来的肯定是普通值,如果reject直接处理,不管你抛出来的是什么东东
914 | x.then(fulfill, reject)
915 | }
916 | return;
917 | }
918 | let called = false;
919 | //2.3.3
920 | //x 是一个thenable
921 | if(x !== null && (typeof x === 'object' || typeof x === 'function')){
922 | try {
923 | //2.3.3.1
924 | let then = x.then;
925 | if (typeof then === 'function') {//2.3.3.3 {then:: (resolve,reject)=>{resolve(1)}}}
926 | then.call(x,(y)=>{
927 | if (called) return
928 | called = true
929 | resolvePromise(promise,y,fulfill,reject)
930 | },(err)=>{
931 | if (called) return
932 | called = true
933 | reject(err)
934 | })
935 | }else{//2.3.3.2 x: {then:1},是一个带then属性的普通值
936 | fulfill(x)
937 | }
938 | }catch(e){//2.3.3.2 可以参见上面说的异常情况2
939 | if (called) return
940 | called = true;
941 | reject(e);
942 | }
943 | }else{//2.3.3.4,x是一个普通值
944 | fulfill(x)
945 | }
946 | }
947 | Promise.prototype.then = function (onFulfilled, onRejected) {
948 | onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
949 | return value
950 | }
951 | onRejected = typeof onRejected === 'function' ? onRejected : function (err) {
952 | throw err
953 | }
954 | let _this = this
955 | let newPromise
956 | if (_this.status === 'resolved') {
957 | newPromise = new Promise(function (resolve, reject) {
958 | process.nextTick(function () {
959 | try {
960 | let x = onFulfilled(_this.value)
961 | resolve(x)
962 | } catch (e) {
963 | reject(e)
964 | }
965 | })
966 | })
967 | }
968 |
969 | if (_this.status === 'rejected') {
970 | newPromise = new Promise(function (resolve, reject) {
971 | process.nextTick(function () {
972 | try {
973 | let x = onRejected(_this.reason)
974 | resolve(x)
975 | } catch (e) {
976 | reject(e)
977 | }
978 | })
979 | })
980 | }
981 |
982 | if (_this.status === 'pending') {
983 | newPromise = new Promise(function (resolve, reject) {
984 |
985 | _this.onResolvedCallbacks.push(function () {
986 | process.nextTick(function () {
987 | try {
988 | let x = onFulfilled(_this.value)
989 | resolve(x)
990 | } catch (e) {
991 | reject(e)
992 | }
993 | })
994 |
995 | })
996 | _this.onRejectedCallbacks.push(function () {
997 | process.nextTick(function () {
998 | try {
999 | let x = onRejected(_this.reason)
1000 | resolve(x)
1001 | } catch (e) {
1002 | reject(e)
1003 | }
1004 | })
1005 | })
1006 |
1007 | })
1008 | }
1009 | return newPromise
1010 | }
1011 | module.exports = Promise
1012 | ```
1013 |
1014 |
1015 |
1016 | ## 测试
1017 |
1018 | 首先你要暴露一个接口:
1019 |
1020 | ```javascript
1021 | Promise.deferred = Promise.defer = function () {
1022 | var dfd = {}
1023 | dfd.promise = new Promise(function (resolve, reject) {
1024 | dfd.resolve = resolve
1025 | dfd.reject = reject
1026 | })
1027 | return dfd
1028 | }
1029 | ```
1030 |
1031 | 使用`promises-aplus-tests`这个库,具体使用方法,请移步它的github去查看吧,不详细介绍了。
1032 |
1033 | ```
1034 | npm install promises-aplus-tests
1035 | promises-aplus-tests myPromise.js
1036 | ```
1037 |
1038 | 测试通过:
1039 |
1040 | 
1041 |
1042 | 完整代码:[https://github.com/yonglijia/JSPI/blob/master/prototype/promise_final_10.js](https://github.com/yonglijia/JSPI/blob/master/prototype/promise_final_10.js)
1043 |
1044 | ## 其他方法
1045 |
1046 | ```javascript
1047 | Promise.prototype.catch = function(callback){
1048 | return this.then(null,callback)
1049 | }
1050 | Promise.resolve = function(value){ //返回一个promise
1051 | return new Promise(function(resolve,reject){
1052 | resolve(value);
1053 | })
1054 | }
1055 | Promise.reject = function(value){//返回一个promise
1056 | return new Promise(function(resolve,reject){
1057 | reject(value);
1058 | })
1059 | }
1060 | Promise.race = function(promise){//只要有一个成功了就resolve,有一个失败了就reject
1061 | return new Promise(function (resolve,reject){
1062 | for(var i = 0;i