When it comes to handwritten promises, there’s a lot of literature out there on the web, and I’ve looked it up, but most of it isn’t complete and some of it isn’t easy to understand, so I decided to write an easy-to-understand Promise from scratch.

To see the full code, please read: Handwritten Promise

Write promises from scratch

The original Promise

First, let’s take a look at what the original Promise might do: print it on the console

console.log(new Promise(
    function(resolve,reject){}));Copy the code

The expansion results are as follows:From the console output, we can clearly see that Promise objects have the following basic methods: Promise.resolve() Promise.reject() Promise.all() Promise.race() Promise.prototype.then() Promise.prototype.catch() Promise.prototype.finally()

  1. Then,catch, and finally are instance methods.
  2. Reject, resolve, All, and race, which belong to the constructor, are static methods.

Promise/A+

If we want to write A Promise by hand, we follow the Promise/A+ specification, and all the Promise libraries in the industry, like ES6 Promise and jQuery Promise, follow this specification.

Start writing

1. Promise core logic implementation

const promise = new Promise((resolve, reject) = > {
   resolve('success')
   reject('err')
})

promise.then(value= > {
  console.log('resolve', value)
}, reason= > {
  console.log('reject', reason)
})
Copy the code

Analyze the basic features of promises:

  1. A Promise is a class that, when executed, passes in an executor that executes immediately
  2. Executor accepts two arguments, resolve and Reject
  3. The default state is pending. “Specification Promise/A+ 2.1”
  • Pending waiting for
  • Fulfilled complete
  • The rejected failure
  1. Store successful state promise has a value of value, can be undefined/thenable/promise; “Specification Promise/A+ 1.3”
  2. Promise has a reason that holds the value of the failed state; “Specification Promise/A+ 1.5”
  3. The status can only be controlled by pending –> depressing or pending –> Rejected. Once the status is changed, it cannot be modified again.
  4. The resolve and reject functions are used in promises to change the state
  5. This is a big pity. The then method will judge the state internally and accept two parameters, which are onFulfilled, the Promise successful callback and onRejected. “Specification Promise/A+ 2.2”
  • If the state is success, the success callback function (ondepressing) is called, with the parameter value of the Promise.
  • If the state is failed, call the failed callback (onRejected) with the argument Reason of the Promise;

Code implementation:

  1. Create a new CustomPromise class and pass in the executor

    / / new CustomPromise. Js
    
    // Create a new CustomPromise class
    class CustomPromise {
      constructor(executor){
        // Executor is an executor that executes immediately upon entry
        executor() 
      }
    }
    Copy the code
  2. Executor passes the resolve and Reject methods as arguments so that the consumer can receive them and call them

// CustomPromise.js

// Create a new CustomPromise class
class CustomPromise	{
	constructor(executor) {
		// Executor is an executor that executes immediately upon entry
		// Pass in the resolve and reject methods
		executor(this.resolve, this.reject)
	}
	// Resolve and reject
	If called directly, the normal function this refers to window or undefined
	// Use the arrow function to make this point to the current instance object

	// Change the status after success
	resolve = () = > {}
	// Change the failed state
	reject = () = >{}}Copy the code
  1. State and result management
// Define three constants to represent the state
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// Create a new CustomPromise class
class CustomPromise	{
  constructor(executor){
    // Executor is an executor that executes immediately upon entry
    // Pass in the resolve and reject methods
    executor(this.resolve, this.reject)
  }

  // Store the state variable. The initial value is pending
  status = PENDING;

  // Value after success
  value = null;
  // The cause of the failure
  reason = null;

  // Change the status after success
  resolve = (value) = > {
    // The status can be updated only when the status is PENDING
    if (this.status === PENDING) {
      // Status changed to successful
      this.status = FULFILLED;
      // Save the value after success
      this.value = value; }}// Change the failed state
  reject = (reason) = > {
    // The status can be updated only when the status is PENDING
    if (this.status === PENDING) {
      // Status changed to failed
      this.status = REJECTED;
      // Cause of save failure
      this.reason = reason; }}}Copy the code
  1. A simple implementation of THEN
// Include a THEN method and accept two parameters onFulfilled and onRejected
CustomPromise.prototype.then = function (onFulfilled, onRejected) {
  // Determine the status
  if (this.status === FULFILLED) {
    // Call the successful callback and return the value
    onFulfilled(this.value);
  } else if (this.status === REJECTED) {
    // Call the failed callback and return the reason
    onRejected(this.reason); }}Copy the code
  1. Exports to expose the CustomPromise class
// CustomPromise.js
module.exports = CustomPromise;
Copy the code

Complete code:

// CustomPromise.js

// Define three constants to represent the state
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

// Create a new CustomPromise class
class CustomPromise {
	constructor(executor) {
		// Executor is an executor that executes immediately upon entry
		// Pass in the resolve and reject methods
		executor(this.resolve, this.reject)
	}

	// Store the state variable. The initial value is pending
	status = PENDING

	// Value after success
	value = null
	// The cause of the failure
	reason = null

	// Resolve and reject
	If called directly, the normal function this refers to window or undefined
	// Use the arrow function to make this point to the current instance object

	// Change the status after success
	resolve = (value) = > {
		// The status can be updated only when the status is PENDING
		if (this.status === PENDING) {
			// Status changed to successful
			this.status = FULFILLED
			// Save the value after success
			this.value = value
		}
	}
	// Change the failed state
	reject = (reason) = > {
		// The status can be updated only when the status is PENDING
		if (this.status === PENDING) {
			// Status changed to failed
			this.status = REJECTED
			// Cause of save failure
			this.reason = reason
		}
	}
}
CustomPromise.prototype.then = function (onFulfilled, onRejected) {
	// Determine the status
	if (this.status === FULFILLED) {
		// Call the successful callback and return the value
		onFulfilled(this.value)
	} else if (this.status === REJECTED) {
		// Call the failed callback and return the reason
		onRejected(this.reason)
	}
}
module.exports = CustomPromise

Copy the code

Validation:

/ / new testCustomPromise. Js

// Import our customPromise.js
const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	resolve('ok')
	reject('error')
})

p.then(
	(value) = > {
		console.info('resolve', value)
	},
	(err) = > {
		console.info('reject', err)
	}
)
// Result: resolve OK
Copy the code

The result is as we expected. The first step is complete. Applause 👏👏👏

Support asynchronous logic in the Promise class

The following features are all test-driven improvements

Add asynchronous logic to the test case, for example:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok')
		reject('error')},1000)
})

p.then(
	(value) = > {
		console.info('resolve', value)
	},
	(err) = > {
		console.info('reject', err)
	}
)
// No information is printed
Copy the code

Analyze the reasons:

The main thread code starts executing, and the sensor (Executor) will execute immediately. However, since setTimeout is a macro task, it will not execute immediately, so the status will not be changed to someday. Then will be executed immediately. In this case, the state is pending, and the onFulfilled or onRejected callback functions will not be executed.

The pending state should be processed in the then function as follows:

  1. Cache success or failure callback
	// Store the success callback function
	onFulfilledCallback = null
	// Store the failed callback function
	onRejectedCallback = null
Copy the code
  1. The processing of pending state in the THEN method stores the callback function
 if (this.status === PENDING) {
	Success and failure callbacks are stored because we do not know how the state will change later
	// Wait until the promise state changes to succeed or fail
	this.onFulfilledCallback = onFulfilled
	this.onRejectedCallback = onRejected
}
Copy the code
  1. Call callbacks in resolve and Reject
	// Change the status after success
	resolve = (value) = > {
		// The status can be updated only when the status is PENDING
		if (this.status === PENDING) {
			// omit other...
			// Determine if the successful callback exists and call it if it does
			this.onFulfilledCallback && this.onFulfilledCallback(value)
		}
	}
	// Change the failed state
	reject = (reason) = > {
		// The status can be updated only when the status is PENDING
		if (this.status === PENDING) {
			// omit other...
			// Determine if the failed callback exists and invoke it if it does
			this.onRejectedCallback && this.onRejectedCallback(reason)
		}
	}
Copy the code

It’s a publish-subscribe model, where you store two functions in then, take them out in Resovle and Reject, and execute them. This approach of collecting dependencies -> triggering notifications -> fetching dependency execution is widely used in the publish-subscribe model.

Validation:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok')
		reject('error')},1000)
})

p.then(
	(value) = > {
		console.info('resolve', value)
	},
	(err) = > {
		console.info('reject', err)
	}
)
// Wait 2 seconds. Resolve OK is displayed
Copy the code

Then method is called many times to add a number of processing functions

Again, take a look at the test script that adds multiple THEN’s

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok')
		reject('error')},1000)
})

p.then((value) = > {
	console.info(1)
	console.info('resolve', value)
})

p.then((value) = > {
	console.info(2)
	console.info('resolve', value)
})

p.then((value) = > {
	console.info(3)
	console.info('resolve', value)
})
/ / 3
// resolve ok
Copy the code

3 resolve OK

Analyze the reasons:

If it is a synchronous callback, the current then returns the current value without any problem. However, when it is an asynchronous callback (like setTimeout above), the callback function in today’s THEN will be stored in a variable, and the value of the later variable will overwrite the previous one. Only ondepressing or onRejected of the last THEN function will be called

Perfect: Store the callback functions in then in an array and iterate through them when the state is resolved or Rejected

  1. Add two new arrays to the class, removing the original callback function variables

    // Store the success callback function
    // onFulfilledCallback = null
    onFulfilledCallbacks = []
    // Store the failed callback function
    // onRejectedCallback = null
    onRejectedCallbacks = []
    Copy the code
  2. In the then function, the callback function is stored in an array

    if (this.status === PENDING) {
    	Success and failure callbacks are stored because we do not know how the state will change later
    	// Wait until the promise state changes to succeed or fail
    	// this.onFulfilledCallback = onFulfilled
    	// this.onRejectedCallback = onRejected
    	this.onFulfilledCallbacks.push(onFulfilled)
    	this.onRejectedCallbacks.push(onRejected)
    }
    Copy the code
  3. The success callback is traversed in resolve and the failure callback is traversed in Reject

// All successful callbacks are executed in resolve
if (this.onFulfilledCallbacks.length) {
	this.onFulfilledCallbacks.forEach((fn) = > fn(value))
}
Copy the code
// reject all successful callbacks
if (this.onRejectedCallbacks.length) {
	this.onRejectedCallbacks.forEach((reason) = > fn(reason))
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok')},1000)
})

p.then((value) = > {
	console.info(1)
	console.info('resolve', value)
})

p.then((value) = > {
	console.info(2)
	console.info('resolve', value)
})

p.then((value) = > {
	console.info(3)
	console.info('resolve', value)
})
/ / 1
// resolve success
/ / 2
// resolve success
/ / 3
// resolve success
Copy the code

4. Chain call of then method

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok')},1000)})function other() {
	return new CustomPromise((resolve, reject) = > {
		resolve('success')
	})
}
p.then((value) = > {
	console.info(1)
	console.info('resolve', value)
	return other()
}).then((value) = > {
	console.info(2)
	console.info('resolve', value)
})
// }).then((value) => {
  ^

// TypeError: Cannot read property 'then' of undefined
Copy the code

TypeError: Cannot read property ‘then’ of undefined

The reason: Then is the method that the CustomPromise instance can call, so the THEN function itself is required to return a CustomePromise object in order to implement the chain call. In addition, the then method returns a return value as the parameter of the next THEN method. If the then method returns a CustomePromise object, the state of the CustomePromise object needs to be determined. Before continuing to execute.

Complete functions:

CustomPromise.prototype.then = function (onFulfilled, onRejected) {
	// To implement the chain call, create a new CustomPromise object and return it
	const promise2 = new CustomPromise((resole, reject) = > {
		// The contents here are in the executor and will be executed immediately
		// Determine the status
		if (this.status === FULFILLED) {
			// Call the successful callback and return the value
			const x = onFulfilled(this.value)
			resolvePromise(x, resole, reject)
		} else if (this.status === REJECTED) {
			// Call the failed callback and return the reason
			onRejected(this.reason)
		} else if (this.status === PENDING) {
			Success and failure callbacks are stored because we do not know how the state will change later
			// Wait until the promise state changes to succeed or fail
			// this.onFulfilledCallback = onFulfilled
			// this.onRejectedCallback = onRejected
			this.onFulfilledCallbacks.push(onFulfilled)
			this.onRejectedCallbacks.push(onRejected)
		}
	})
	return promise2
}

function resolvePromise(x, resolve, reject) {
	// Determine if x is a CustomPromise instance object
	if (x instanceof CustomPromise) {
		// Call the THEN method. The purpose is to change the current promise state to fulfilled or Rejected after the internal promise state is switched
		// x.then(value => resolve(value), reason => reject(reason))
		// After simplification
		x.then(resolve, reject)
	} else {
		/ / common values
		resolve(x)
	}
}
/ / 1
// resolve ok      
/ / 2
// resolve2 success
Copy the code

The resolve and reject in resolvePromise is to cut the promise newly generated by the THEN function into a big pity or rejected. Otherwise, when executing the next THEN, the newly generated promise state will always be pending. The callback function is not called, and the parameter value is passed to the next then function

The then method chain calls identify whether a Promise returns itself

Print the following on the console:

const promise = new Promise((resolve, reject) = > {
  resolve(100)})const p1 = promise.then(value= > {
  console.log(value)
  return p1
})
// undefined
// editor.csdn.net/:1 Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
Copy the code

If the then method returns its own Promise object, a circular call will occur, at which point the program will report an error

Complete functions:

Pass the newly generated promise from the then function as an argument to the resolvePromise

 // resolvePromise is processed centrally, passing in the newly generated promise
resolvePromise(promise2, x, resolve, reject);
Copy the code
function resolvePromise(promise2, x, resolve, reject) {
  // If it is equal, return itself, throws a type error, and returns
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if(x instanceof MyPromise) {
    x.then(resolve, reject)
  } else{
    resolve(x)
  }
}
Copy the code

Verification: error

return p1
^

ReferenceError: Cannot access 'p1' before initialization  
Copy the code

We need to wait for the initialization of promise2 to complete. Create an asynchronous function to wait for promise2 to complete initialization. Most people use setTimeout online. Personally, I suggest using queueMicrotask, because setTimeout is a macro task, while queueMicrotask and promise are microtasks

Modification:

// Create a microtask and wait for the initialization of promise2 to complete
queueMicrotask(() = > {
	// Call the successful callback and return the value
	const x = onFulfilled(this.value)
	// Pass in resolvePromise
	resolvePromise(promise2, x, resolve, reject)
})  
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	resolve('ok')})const p1 = p.then((value) = > {
	console.info(1)
	console.info('resolve', value)
	return p1
})

p1.then(
	(value) = > {
		console.info(2)
		console.info('resolve', value)
	},
	(reason) = > {
		console.info(reason)
	}
)
/ / 1
// resolve ok
// TypeError: Chaining cycle detected for promise #<Promise>
Copy the code

Catch errors

  1. Catch the code in the executor. If there is a code error in the executor, then the state of the Promise changes to failed.

    constructor(executor) {
    	// Executor is an executor that executes immediately upon entry
    	// Pass in the resolve and reject methods
    	try {
    		executor(this.resolve, this.reject)
    	} catch (error) {
    		// If there is an error, execute reject
    		this.reject(error)
    	}
    }
    Copy the code

    Validation:

    const CustomPromise = require('./CustomPromise')
    const p = new CustomPromise((resolve, reject) = > {
    	throw new Error('Actuator error')
    })
    
    p.then(
    	(value) = > {
    		console.info(1)
    		console.info('resolve', value)
    	},
    	(reason) = > {
    		console.info(2)
    		console.info(reason.message)
    	}
    )
    / / 2
    // Actuator error
    Copy the code
  2. Error capture at execution time of THEN

    Complete functions:

    // Create a microtask and wait for the initialization of promise2 to complete
    queueMicrotask(() = > {
    	try {
    		// Call the successful callback and return the value
    		const x = onFulfilled(this.value)
    		// Pass in resolvePromise
    		resolvePromise(promise2, x, resolve, reject)
    	} catch (err) {
    		reject(err)
    	}
    })
    Copy the code

    Validation:

    const CustomPromise = require('./CustomPromise')
    const p = new CustomPromise((resolve, reject) = > {
    	resolve('ok')
    })
    
    p.then(
    	(value) = > {
    		console.info(1)
    		console.info('resolve', value)
    		throw new Error('callback error')},(reason) = > {
    		console.info(2)
    		console.info(reason.message)
    	}
    ).then(
    	(value) = > {
    		console.info(3)
    		console.info(value)
    	},
    	(err) = > {
    		console.info(4)
    		console.info(err.message)
    	}
    )
    / / 1
    // resolve ok
    / / 4
    // callback error
    
    Copy the code

7. Refer to the processing mode in the fulfilled state, and modify the Rejected and pending states

Complete functions:

CustomPromise.prototype.then = function (onFulfilled, onRejected) {
	// To implement the chain call, create a new CustomPromise object and return it
	const promise2 = new CustomPromise((resolve, reject) = > {
		// The contents here are in the executor and will be executed immediately
		const fulfilledMicrotask = () = > {
			// Create a microtask and wait for the initialization of promise2 to complete
			queueMicrotask(() = > {
				try {
					// Call the successful callback and return the value
					const x = onFulfilled(this.value)
					// Pass in resolvePromise
					resolvePromise(promise2, x, resolve, reject)
				} catch (err) {
					reject(err)
				}
			})
		}

		const rejectedMicrotask = () = > {
			// Create a microtask and wait for the initialization of promise2 to complete
			queueMicrotask(() = > {
				try {
					// Call the failed callback and return the reason
					const x = onRejected(this.reason)
					// Pass in resolvePromise
					resolvePromise(promise2, x, resolve, reject)
				} catch (err) {
					reject(err)
				}
			})
		}
		// Determine the status
		if (this.status === FULFILLED) {
			fulfilledMicrotask()
		} else if (this.status === REJECTED) {
			rejectedMicrotask()
		} else if (this.status === PENDING) {
			this.onFulfilledCallbacks.push(fulfilledMicrotask)
			this.onRejectedCallbacks.push(rejectedMicrotask)
		}
	})
	return promise2
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	resolve('ok')
})

p.then(
	(value) = > {
		console.info(1)
		console.info('resolve', value)
		throw new Error('callback error')},(reason) = > {
		console.info(2)
		console.info(reason.message)
	}
)
	.then(
		(value) = > {
			console.info(3)
			console.info(value)
		},
		(err) = > {
			console.info(4)
			console.info(err.message)
			return err.message
		}
	)
	.then((value) = > {
		console.info(5)
		console.info(value)
		throw new Error('err') // Enter onRejected in the next THEN
		// Return new Error('err') // Enter ondepressing in the next then
	})
	.then(
		(value) = > {
			console.info(6)
			console.info(value)
		},
		(err) = > {
			console.info(7)
			console.info(err.message)
		}
	)
/ / 1
// resolve ok
/ / 4
// callback error
/ / 5
// callback error
/ / 7
// err

Copy the code

Parameters in then become optional

This is a pity callback function, which will default to value=>value when onFulfilled callback function is not introduced, default to reason => {throw reason}

Complete functions:

CustomPromise.prototype.then = function (onFulfilled, onRejected) {
	// If not, use the default function
	onFulfilled =
		typeof onFulfilled === 'function' ? onFulfilled : (value) = > value
	onRejected =
		typeof onRejected === 'function'
			? onRejected
			: (reason) = > {
					throw reason
			  }
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
const p = new CustomPromise((resolve, reject) = > {
	resolve('ok')
})
p.then()
	.then()
	.then((value) = > console.log(value))
// ok
Copy the code
const MyPromise = require('./CustomPromise')
const promise = new MyPromise((resolve, reject) = > {
  reject('err')
})
 
promise.then().then().then(value= > console.log(value), reason= > console.log(reason))
// err
Copy the code

Resolve and Reject static calls

const CustomPromise = require('./CustomPromise')
CustomPromise.resolve()
	.then(() = > {
		console.log(0)
		return CustomPromise.resolve(4)
	})
	.then((res) = > {
		console.log(res)
	})
// CustomPromise.resolve()
/ / ^

// TypeError: CustomPromise.resolve is not a function
Copy the code

It turns out, unsurprisingly, that these static methods are not defined at all

Complete functions:

// resolve static method
static resolve(parameter) {
	// If you pass in CustomPromise, return it directly
	if (parameter instanceof CustomPromise) {
		return parameter
	}

	// Switch to normal mode
	return new CustomPromise((resolve) = > {
		resolve(parameter)
	})
}

// reject static methods
static reject(reason) {
	return new CustomPromise((resolve, reject) = > {
		reject(reason)
	})
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
CustomPromise.resolve()
	.then(() = > {
		console.log(0)
		return CustomPromise.resolve(4)
	})
	.then((res) = > {
		console.log(res)
	})
/ / 0
/ / 4
Copy the code

9. Make up the Promise API

  1. catch

Promise.prototype. Catch An exception used to catch a Promise, equivalent to an unsuccessful then.

Complete functions:

CustomPromise.prototype.catch = function (errCallback) {
	return this.then(null, errCallback)
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
CustomPromise.resolve(
	new CustomPromise((resolve, reject) = > {
		setTimeout(() = > {
			reject('fail')},1000)
	})
)
	.then((value) = > {
		console.info(value, 'value')
	})
	.catch((err) = > {
		console.info(err, 'err')})// fail err
Copy the code
  1. finally

Finally does not mean final, but will be executed anyway. A finally callback is executed in both a success callback and a failure callback for then. If it is a success callback for THEN, the result is returned. If it is a failed callback into THEN, the result of the failure is passed to the catch.

Complete functions:

CustomPromise.prototype.finally = function (callback) {
	return this.then(
		(value) = > {
			return CustomPromise.resolve(callback()).then(() = > value)
		},
		(reason) = > {
			return CustomPromise.resolve(callback()).then(() = > {
				throw reason
			})
		}
	)
}

Copy the code

Validation:

CustomPromise.resolve(456)
	.finally(() = > {
		return new CustomPromise((resolve, reject) = > {
			setTimeout(() = > {
				resolve(123)},3000)
		})
	})
	.then((data) = > {
		console.log(data, 'success')
	})
	.catch((err) = > {
		console.log(err, 'error')})// 456 success
Copy the code
  1. all

Promise. all is designed to solve the problem of concurrency. Multiple asynchronous concurrent processes get the final result (if one fails).

CustomPromise.all = function (values) {
	if (!Array.isArray(values)) {
		const type = typeof values
		return new TypeError(`TypeError: ${type} ${values} is not iterable`)}return new CustomPromise((resolve, reject) = > {
		let resultArr = []
		let orderIndex = 0
		const processResultByKey = (value, index) = > {
			resultArr[index] = value
			if (++orderIndex === values.length) {
				resolve(resultArr)
			}
		}
		for (let i = 0; i < values.length; i++) {
			let value = values[i]
			if (value && typeof value.then === 'function') {
				value.then((value) = > {
					processResultByKey(value, i)
				}, reject)
			} else {
				processResultByKey(value, i)
			}
		}
	})
}
Copy the code

Validation:

const CustomPromise = require('./CustomPromise')
let p1 = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok1')},1000)})let p2 = new CustomPromise((resolve, reject) = > {
	setTimeout(() = > {
		resolve('ok2')},1000)
})

CustomPromise.all([1.2.3, p1, p2]).then(
	(data) = > {
		console.log('resolve', data)
	},
	(err) = > {
		console.log('reject', err)
	}
)
// Output after 1s
// resolve [ 1, 2, 3, 'ok1', 'ok2' ]
Copy the code
  1. race

Complete functions:

static race(promises) {
	return new CustomPromise((resolve, reject) = > {
		// The for loop is executed together
		for (let i = 0; i < promises.length; i++) {
			let val = promises[i]
			if (val && typeof val.then === 'function') {
				val.then(resolve, reject)
			} else {
				/ / common values
				resolve(val)
			}
		}
	})
}
Copy the code