1. Terminology

  1. “Promise” is an object or function with athen method whose behavior conforms to this specification.
  2. “Thenable” is an object or function that defines men’s climatethen method.
  3. “Value” is any legal JavaScript value (includingundefined, a thenable, or a promise).
  4. “Exception” is a value that is thrown using thethrow statement.
  5. “Reason” is a value that indicates why a promise was rejected.

2. Requirements

2.1 Promise States

A promise must be in one of three states: pending, fulfilled, or rejected.

To prevent future string errors, we write three constants to represent these three states

const PENDING =  'pending';
const FULFILLED =  'fulfilled';
const REJECTED =  'rejected';
Copy the code

2.1.1 When pending, a promise:

  1. may transition to either the fulfilled or rejected state.

This is a big pity, a promise:

  1. must not transition to any other state.

  2. must have a value, which must not change.

2.1.3 When rejected, a promise:

  1. must not transition to any other state.

  2. must have a reason, which must not change.

Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.

class Promise {
  constructor(executor) {
    this.status = PENDING

    let resolve = data= > {
      if (this.status === PENDING){
        this.status = FULFILLED
        this.value = data
      }
    }
    let reject = reason= > {
      if (this.status === PENDING){
        this.status = REJECTED
        this.value = reason
      }
    }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
}
Copy the code

2.2 The then Method

A promise must provide a then method to access its current or eventual value or reason.

Accepts two arguments for A Promise’s then Method:

promise.then(onFulfilled, onRejected)
Copy the code

So let’s write it now

class Promise {
  constructor(executor) {
    // ...
  }
  then(onFulfilled, onRejected) {

  }
}
Copy the code

2.2.1 to BothonFulfilled and onRejected are optional arguments

  1. If onFulfilled is not a function, it must be ignored.

  2. If onRejected is not a function, it must be ignored.

class Promise {
  constructor(executor) {
    // ...
  }
  then(onFulfilled, onRejected) {
   onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
   onRejected = typeof onRejected == 'function' ? onRejected : reason= > { throw reason }
   // If the code executes here, onFulfilled and onRejected must be functions}}Copy the code

If not, we ignore the user’s value and use our internal custom function.

The reason for the above implementation will be explained again later

2.2.2 the IfonFulfilled is a function

  1. it must be called after promise is fulfilled, with promise‘s value as its first argument.

  2. it must not be called before promise is fulfilled.

  3. it must not be called more than once.

If the state of the Promise is very depressing when we bind the callback function to the Promise by then, we will execute the passed callback function directly

then(onFulfilled,onRejected){
  if (this.status === FULFILLED) {
    onFulfilled(this.value)
  }
}
Copy the code

2.2.3 the IfonRejected is function

  1. it must be called after promise is rejected, with promiseS reason as its first argument.

  2. it must not be called before promise is rejected.

  3. it must not be called more than once.

then(onFulfilled,onRejected){
  if (this.status === REJECTED) {
    onRejected(this.value)
  }
}
Copy the code

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

3.1 Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures thatconFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, Or with a “micro-task” mechanism such as MutationObserver or process.nexttick. Since the promise implementation is considered platform code, It may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

This callback function must be called asynchronously, which is onFulfilled and onRejected. Here we use the simplest way, that is, setTimeout.

This is a pity and onFulfilled code. Put it in setTimeout so that it won’t happen immediately. The callback function can be executed asynchronously.

if (this.status === FULFILLED) {
  let timer = setTimeout((a)= > {
    clearTimeout(timer)
    onFulfilled(this.value)
  })
  }
if (this.status === REJECTED) {
  let timer = setTimeout((a)= > {
    clearTimeout(timer)
    onRejected(this.value)
  })
  }
Copy the code

2.2.5 onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]

3.2 That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.

2.2.6 then may be called multiple times on the same promise.

In the case we dealt with above, the corresponding callback is executed when the function has succeeded or failed

The state is still pending when the callback is added, so we should not execute the callback function

In addition, we can then apply the same Promise object multiple times, that is, mount multiple success or failure callbacks on the object

The promise is executed when it succeeds or fails.

We need to cache it before we can execute it

So we set up two arrays to hold callback functions

class Promise {
  constructor(executor) {
    // Define the callback array to execute after the store succeeds
    this.onResolvedCallbacks = []
    // Define an array of callbacks to execute after a failure
    this.onRejectedCallbacks = []
  }
}
Copy the code

When executing THEN, if the Promise state is still pending, the method is pushed into the array above.

Promise{
  // ...
  then(){
    // ...
    if (this.state === PENDING) {
      preomise2 = new Promise((resolve, reject) = > {
        this.onResolvedCallbacks.push(onFulfilled)
        this.onRejectedCallbacks.push(onRejected)
      })
    }
    // ...}}Copy the code
  1. If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.

  2. If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.

So when we change the state, resolve and Reject, we start iterating through the callback array

class Promise {
  constructor(executor) {
    // ...
    this.onResolvedCallbacks = []
    this.onRejectedCallbacks = []

    let resolve = data= > {
      // ..
      this.onResolvedCallbacks.forEach(cb= > cb(this.value))
      // ..
    }

    let reject = reason= > {
      // ..
      this.onRejectedCallbacks.forEach(cb= > cb(this.value))
      // ..
    }
    // ...

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
}
Copy the code

But let’s go back

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code.

Our callback function needs to execute asynchronously, whereas the above code executes synchronously, so we need to use setTimeout here to execute asynchronously

The CB obtained through the code above is our onFulfilled and onRejected.

class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.onResolvedCallbacks = []
    this.onRejectedCallbacks = []

    let resolve = data= > {
      let timer = setTimeout((a)= > {
        clearTimeout(timer)
        if (this.status === PENDING) {
          this.status = FULFILLED
          this.value = data
          // Iterate through the successful callback
          this.onResolvedCallbacks.forEach(cb= > cb(this.value))
        }
      })
      }
    
    let reject = reason= > {
      let timer = setTimeout((a)= > {
        clearTimeout(timer)
        if (this.status === PENDING) {
          this.status = REJECTED
          this.value = reason
          // Iterate over the failed callback
          this.onRejectedCallbacks.forEach(cb= > cb(this.value))
        }
      })
      }

    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
}
Copy the code

2.2.7 then must return a promise [3.3].

3.3 Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1and under what conditions.

 promise2 = promise1.then(onFulfilled, onRejected);
Copy the code

All of our previous actions should wrap promise2 = new Promise(resolve, reject) =>{} and return promise2

Resolve (value) and promise2.reject (reason) are used to pass data back to our callback function

We can get the data in the following form

let promise2 = new Promise((resolve, reject) = > {
  resolve('data')
  reject('reason')
})
promise2.then(
  data= > console.log(data),
  reason => console.log(reason)
)
Copy the code

So now we’re wrapping up the code in promises

then(onFulfilled, onRejected) {
  // ...
  let promise2

  if (this.status === FULFILLED) {
    promise2 = new Promise((resolve, reject) = > {
      // ...})}if (this.status === REJECTED) {
    promise2 = new Promise((resolve, reject) = > {
      // ...})}if (this.status === PENDING) {
    promise2 = new Promise((resolve, reject) = > {
      // ...})}return promise2
}
Copy the code

1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).

Here we need to define a [[Resolve]](promise2, x) method, which we’ll call resolvePromise,

function resolvePromise(promise2, x, resolve, reject) {}Copy the code

It is used to resolve promises. How to resolve promises will be explained in 2.3

This method is used to parse the value returned by the callback function, and we want the value passed through resolve and reject to be a normal value, that is, non-Thenable, which we’ll discuss later.

2. If either onFulfilled or onRejected throws an exception e.promise2 must be rejected with e as the reason.

If it’s an error, it must be a normal value, so we just pass it in preject

if (this.status === FULFILLED) {
  promise2 = new Promise((resolve, reject) = > {
    let timer = setTimeout((a)= > {
      clearTimeout(timer)
      try {
        let x = onFulfilled(this.value)
        resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
    })
}

if (this.status === REJECTED) {
  promise2 = new Promise((resolve, reject) = > {
    let timer = setTimeout((a)= > {
      clearTimeout(timer)
      try {
        let x = onRejected(this.value)
        resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
    })
}

if (this.status === PENDING) {
  promise2 = new Promise((resolve, reject) = > {
    this.onResolvedCallbacks.push(value= > {
      try {
        let x = onFulfilled(value)
        resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
    this.onRejectedCallbacks.push(reason= > {
      try {
        let x = onRejected(reason)
        resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
  })
}
Copy the code

3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.

4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

This is what I said earlier. If the onFulFilled and onRejected that the user passes in are not functions, we will ignore them and define them as internal functions

onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value
onRejected = typeof onRejected == 'function' ? onRejected : reason= > { throw reason }
Copy the code

In simple terms, the value is tossed backwards so that the next THEN can retrieve the data from that THEN.

Promise
  .resolve(4)
  .then()
  .then(val= > console.log(val))
Copy the code

To sum up, we have implemented all the code for the THEN method

then(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
  onRejected = typeof onRejected == 'function' ? onRejected : reason= > { throw reason };
  let promise2

  if (this.status === FULFILLED) {
    promise2 = new Promise((resolve, reject) = > {
      let timer = setTimeout((a)= > {
        clearTimeout(timer)
        try {
          let x = onFulfilled(this.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
      })
  }
  if (this.status === REJECTED) {
    promise2 = new Promise((resolve, reject) = > {
      let timer = setTimeout((a)= > {
        clearTimeout(timer)
        try {
          let x = onRejected(this.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
      })
  }
  if (this.status === PENDING) {
    promise2 = new Promise((resolve, reject) = > {
      this.onResolvedCallbacks.push(value= > {
        try {
          let x = onFulfilled(value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
      this.onRejectedCallbacks.push(reason= > {
        try {
          let x = onRejected(reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    })
  }

  return promise2
};
Copy the code

Let’s look at the resolvePromise we defined earlier

2.3 The Promise Resolution Procedure

Now let’s look at parsing the promise process, which we just wrote

function resolvePromise(promise2, x, resolve, reject) {}Copy the code

So what do promise2 and x point to

When we execute the then method, we return a new Promise, promise2

let p1 = new Promise((resolve, reject) = > {resolve('data')})
let promise2 = p1.then(data= > {
  x = data + 'It's been treated p1'.
  return x
})
console.log(promise2); // Promise { <pending> }
promise2.then(data= > console.log(data)) // Data is processed by P1
Copy the code
  • promise2Refers to,p1.thenThe object returned by the
  • xRefers to thep1.thentop1The value returned after the added callback function is executed

If x were a normal value, just like we printed it out

But x might be a Thenable object

let p1 = new Promise((resolve, reject) = > { resolve('data')})let promise2 = p1.then((a)= > {
  let x = new Promise((resolve, reject) = > { resolve('X is a promise.')})return x
}
                      )
promise2.then(data= > {
  console.log(data); //x is a promise
})
Copy the code

New Promise((resolve, reject) => {resolve(‘x is a Promise ‘)})

Because if the value returned was a Thenable object, we would parse it to a normal value and return it

// ...
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject) // The return value of the callback function is parsed
// ...
Copy the code

ResolvePromise purpose is that if x is the common value of the direct execution promise2. Resolve (x), if not normal value after parsing, until he had converted to common value x and then perform promise2. Resolve (x), of course, as long as it is a mistake is executed directly promise2 .reject(x)

So how do we resolve it to ordinary values is what we’re going to do

2.3.1 the Ifpromise and x refer to the same object, reject promise with a TypeError as the reason.

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Circular reference')); }}Copy the code

Circular references

let p1 = new Promise((resolve, reject) = > {
  resolve()
})
let p2 = p1.then((a)= > p2)
p2.then(null, reason => {
  console.log(reason); // TypeError: circular reference
})
Copy the code

Then (() => p2) => p2; then() => p2

2.3.2 If x is a promise, adopt its state [3.4] :

[3.3] Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.

  1. If x is pending, promise must remain pending until x is fulfilled or rejected.

    If X is a Promise, we must wait for it to complete (fail or succeed) and get a normal value before we can proceed.

    We simply place the task to be executed in the success callback and failure callback of x. Teng (), which means that x will call our code when it completes.

    • If yes, run the commandpromise2theResolve (value)
  • If the command fails, execute the commandpromise2thereject(reason)

In the success case, however, we need to consider that x. Chen’s success callback argument, which we call y, may also be a Thenable object

So we should change the top to

  • If yes, run the commandresolvePromise(promise2, y, resolve, reject)

The value in promise2. Resolve (value) must be a non-Thenable object

In the resolvePromise function, resolve(x) is executed if x is not a thenable object to end the recursion.

This is part of the later specification, which will be covered later

if (x instanceof Promise) {
  if (x.status == PENDING) {
    x.then(
      y= > resolvePromise(promise2, y, resolve, reject),
      r => reject(r)
      // reject // This is also possible, but to be symmetric, the reject is wrapped in a function)}}Copy the code

In the above code y is the successful return value of x (x is the Promise object) if y is a normal value

  1. If/when x is fulfilled, fulfill promise with the same value.

  2. If/when x is rejected, reject promise with the same reason.

if (x instanceof Promise) {
  if (x.status == PENDING) {
    x.then(
      y= > { resolvePromise(promise2, y, resolve, reject) },
      r => reject(r)
    )
  } else x.then(resolve, reject);
}
Copy the code

If x is complete, we pass resolve and reject, and it executes immediately. If x is complete, it must be normal

2.3.3 Otherwise, the ifx is an object or function,

The following processing is for compatibility processing. When our promise interacts with other promises, their promises may be written by ourselves or referenced by third-party libraries, so we cannot directly use X instanceof promise to determine, so we call them Thanable

Thenable, which means that an object or function has a then method, is represented as a piece of code

if(p ! = =null &&
    (typeof p === 'object' ||typeof p === 'function') &&
    typeof p.then === 'function') {
  / / p for thenable
} else {
  // p is not thenable
}
Copy the code

Of course, the native promise must be a Thenable.

If thenable’s logic is implemented, x is a promise and can be deleted.

Let’s start with thenable

if (x instanceof Promise) {
  // ...
} else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
  // ...
}
Copy the code
  1. Let then be x.then.3.5]

else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
  let then = x.then;
}
Copy the code

3.5 This procedure of first storing a reference to X. teng, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals.

What we mean by that is we don’t decide if then is a method, we’ll decide later.

  1. If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.

    When we get X. Chen, an error may be reported, so we need to try/catch it, reject if it is reported

    Of course, normally no error is reported, and the following code demonstrates this

let obj = {}
Object.defineProperty(obj, 'then', {
  get() {
    throw Error('Then error')
    return function (onFulfilled, onReject) {
    }
  },
  set() { }
})
console.log(obj.then());
Copy the code

So where x. Chen is retrieved above, it should be wrapped in a try/catch

else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
  try{
    let then = x.then;
  }catch(e){
    reject(e)
  }
}
Copy the code
  1. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:

    1. If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
    2. If/when rejectPromise is called with a reason r, reject promise with r.
    else 	if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
      try {
        let then = x.then;
        if (typeof then === 'function') {
          then.call(
            x,
            y => resolvePromise(promise2, y, resolve, reject),
            r => reject(r)
          )
        }
      } catch (e) {
        reject(e)
      }
    }
    Copy the code

    This with x as then essentially executes the following code

    x.then(
      y= > { resolvePromise(promise2, y, resolve, reject) },
      r => reject(r)
    )
    Copy the code

    We’ll see that the code does exactly what we did when X was a promise

    1. If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.

    That is, either a resolvePromise or a rejectPromise can only be implemented because to comply with a state, either a

    • Pending – fulfilled

    • Pending – rejected

    • Pending can only be changed once

    If both a resolvePromise and a rejectPromise are executed at the same time, pending changes twice

    So, we use a variable called to limit

    if (x instanceof Promise) {
      // ...
    } else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
      // whether promise2 is resolved or reject
      let called = false;
      try {
        let then = x.then;
        if (typeof then == 'function') {
          then.call(
            x,
            y => {
              // Prevent promise from executing both successful and failed callbacks
              // If promise2 has already succeeded or failed, it is no longer processed
              if (called) return;
              called = true;
              resolvePromise(promise2, y, resolve, reject);
            },
            r => {
              // Prevent promise from executing both successful and failed callbacks
              // If promise2 has already succeeded or failed, it is no longer processed
              if (called) return;
              called = true;
              reject(r);
            });
        } catch (e) {
          // ...}}Copy the code
    1. If calling then throws an exception e.
      1. If resolvePromise or rejectPromise have been called, ignore it.
      2. Otherwise, reject promise with e as the reason.

      Similarly, we’re reporting errors and we need to restrict that

    if (x instanceof Promise) {
      // ...
    } else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
      // whether promise2 is resolved or reject
      let called = false;
      try {
        // ...
      } catch (e) {
        // Prevent promise from executing both successful and failed callbacks
        // If promise2 has already succeeded or failed, it is no longer processed
        if (called) return;
        called = true; reject(e); }}Copy the code
  2. If then is not a function, fulfill promise with x.

If x is an object or function, but x. teng is not a method, then x does not comply with Thenable’s definition that x is a common value

For normal values, we’ll just resolve

function resolvePromise(promise2, x, resolve, reject) {
  // ...
  if (x instanceof Promise) {
    // ...
  } else if(x ! =null && ((typeof x == 'object' || typeof x == 'function'))) {
    try {
      // ...
      if (typeof then == 'function') {
        // ...
      } else {
        // Then is not a functionresolve(x); }}catch (e) {
      // ...}}else{
      // ...}}Copy the code

We can take an example

let p1 = Promise.resolve(1)
let p2 = p1.then((a)= > {
  return {
    name: 'wcdaren'.then: 'Not the way'
  }
})
p2.then(
  data= > console.log(`data:${data}`),
  error => console.log(`error:${error}`))Copy the code

The above returns an object, but the THEN property is not a function

2.3.4 If x is not an object or function, fulfill promise with x.

if (x instanceof Promise) {
  // ...
} else if(x ! =null && ((typeof x == 'object') | | (typeof x == 'function'))) {
  // ...
} else {
  // x is a normal value
  resolve(x);
}
Copy the code

The x here is the simplest, non-promise, non-thenable, we just resovle it.

That’s what happened to him

let p1 = Promise.resolve(1)
let p2 = p1.then((a)= > 1) // x is the 1 here, and it goes resovle of p2
p2.then(
  data= > console.log('p2.resvole', data), // Execute p2's resolve
  e => console.log('p2.reject', e)
)
// p2.resvole 1
Copy the code

test

We add the following code later

Promise.deferred = Promise.defer = function () {
  var defer = {};
  defer.promise = new Promise(function (resolve, reject) {
    defer.resolve = resolve;
    defer.reject = reject;
  })
  return defer;
}
try {
  module.exports = Promise
} catch (e) {
}
Copy the code

Using scripted tests

npm i -g promises-aplus-tests
promises-aplus-tests Promise.js
Copy the code

With full code

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
	if (promise2 === x) {
		return reject(new TypeError('Circular reference'));
	}
	let then
	let called = false
	if (x instanceof Promise) {
		if (x.status == PENDING) {
			x.then(
				y= > resolvePromise(promise2, y, resolve, reject),
				r => reject(r)
			)
		} else x.then(resolve, reject);
	} else if(x ! =null && ((typeof x == 'object' || typeof x == 'function'))) {
		try {
			then = x.then;
			if (typeof then == 'function') {
				then.call(
					x,
					y => {
						// Prevent promise from executing both successful and failed callbacks
						// If promise2 has already succeeded or failed, it is no longer processed
						if (called) return;
						called = true;
						resolvePromise(promise2, y, resolve, reject);
					},
					r => {
						// Prevent promise from executing both successful and failed callbacks
						// If promise2 has already succeeded or failed, it is no longer processed
						if (called) return;
						called = true;
						reject(r);
					});
			} else{ resolve(x); }}catch (e) {
			if (called) return;
			called = true; reject(e); }}else{ resolve(x); }}class Promise {
	constructor(executor) {
		// Set the state
		this.status = PENDING
		this.value = undefined
		// Define the callback array to execute after the store succeeds
		this.onResolvedCallbacks = []
		// Define an array of callbacks to execute after a failure
		this.onRejectedCallbacks = []

		let resolve = data= > {
			let timer = setTimeout((a)= > {
				clearTimeout(timer)
				if (this.status === PENDING) {
					this.status = FULFILLED
					this.value = data
					this.onResolvedCallbacks.forEach(cb= > cb(this.value))
				}

			})
		}
		let reject = reason= > {
			let timer = setTimeout((a)= > {
				clearTimeout(timer)
				if (this.status === PENDING) {
					this.status = REJECTED
					this.value = reason
					this.onRejectedCallbacks.forEach(cb= > cb(this.value))
				}
			})
		}

		try {
			executor(resolve, reject)
		} catch (error) {
			reject(error)
		}
	}
	then(onFulfilled, onRejected) {
		onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value= > value;
		onRejected = typeof onRejected == 'function' ? onRejected : reason= > { throw reason };
		let promise2

		if (this.status === FULFILLED) {
			promise2 = new Promise((resolve, reject) = > {
				let timer = setTimeout((a)= > {
					clearTimeout(timer)
					try {
						let x = onFulfilled(this.value)
						resolvePromise(promise2, x, resolve, reject)
					} catch (e) {
						reject(e)
					}
				})
			})
		}
		if (this.status === REJECTED) {
			promise2 = new Promise((resolve, reject) = > {
				let timer = setTimeout((a)= > {
					clearTimeout(timer)
					try {
						let x = onRejected(this.value)
						resolvePromise(promise2, x, resolve, reject)
					} catch (e) {
						reject(e)
					}
				})
			})
		}
		if (this.status === PENDING) {
			promise2 = new Promise((resolve, reject) = > {
				this.onResolvedCallbacks.push(value= > {
					try {
						let x = onFulfilled(value)
						resolvePromise(promise2, x, resolve, reject)
					} catch (e) {
						reject(e)
					}
				})
				this.onRejectedCallbacks.push(reason= > {
					try {
						let x = onRejected(reason)
						resolvePromise(promise2, x, resolve, reject)
					} catch (e) {
						reject(e)
					}
				})
			})
		}

		return promise2
	}
}

/ / test
Promise.deferred = Promise.defer = function () {
	var defer = {};
	defer.promise = new Promise(function (resolve, reject) {
		defer.resolve = resolve;
		defer.reject = reject;
	})
	return defer;
}
try {
	module.exports = Promise
} catch (e) {
}
Copy the code