1. Pre-knowledge

1.1 Function objects and Instance objects

1. Function object: When a function is used as an object, it is simply called function object

2. Instance objects: Objects generated by the new constructor are simply instance objects

Example:

function Fn() {  // Fn is a function
}
const fn = new Fn()  // Fn is the constructor. New returns the instance object
console.log(Fn.prototype)  // Fn is a function object
console.log(Fn.call({}))   // Fn is a function object

$('#test')  // $is a function
$.ajax()   $is the function object
Copy the code

conclusion

Left of dot: left of object () : function

extension

A ()[0]()() a function returns the first element in the array, calls it, returns the function again, and calls it againCopy the code

1.2 Classification of callback functions

  1. Synchronous callback:

1. Understanding: Execute immediately, complete execution, not put into callback queue

2. Example: Array traversal related callback function/Promise’s excutor function

2). Asynchronous callback:

1. Understanding: It will not be executed immediately, but will be placed in the callback queue for future execution

2. Example: timer callback/ajax callback/Promise success | failure callback

Example:

const arr = [1.2.3]
arr.forEach(item= > {  ForEach () does not execute until all callbacks have been executed
  console.log('forEach callback()', item)
})
console.log('the forEach ()')

setTimeout(() = > {  // Asynchronously executed callback functions are placed after the callback queue, and setTimeout() is executed before the callback is executed
  console.log('setTimeout callback()')},0)
console.log('the setTimeout ()')
Copy the code

The attached:

  • There are three criteria for determining a callback function:

    1. Self-defined

    2. No manual call is required

    3. But they did

1.3 Error in JS

1. Wrong type

Error: Parent type of all errors

ReferenceError: The variable referenced does not exist

TypeError: Error indicating that the data type is incorrect

RangeError: Data values are not in the range allowed

SyntaxError: indicates a SyntaxError

2. Error handling

Catch error: try… catch

Throw error: Throw error

3. Error object

Message property: error information

Stack property: Function call stack record information

Example:

  1. Common built-in error
// ReferenceError: The referenced variable does not exist
console.log(a) // ReferenceError: a is not defined
console.log('After the error')

// TypeError: error with incorrect data type
let b = null
console.log(b.xxx) // TypeError: Cannot read property 'xxx' of null
let b = {}
console.log(b.xxx) // undefined
b.xxx() // TypeError: b.xxx is not a function
b()

// RangeError: The data value is not in the allowed range
function fn() { // Infinite recursion
  fn()
} // RangeError: Maximum call stack size exceeded
fn()

// SyntaxError: SyntaxError
const c = """" // SyntaxError: Unexpected string

let d = 3
console.log(d.xxx)  // new Number(d). XXX output undefined
Copy the code

2. Error handling

/* Catch error */
try {
  const e = {}
  e()
} catch (error) {
  console.log(error.message)
  console.log(error.stack)
}


/* Throws error */
function doThing() {  // If the current time is odd, we can work normally, otherwise we can't work
  const time = Date.now()
  if (time % 2= =1) {
    console.log('The current time is odd and works well.... ' + time)
  } else {  // Can't work, must tell the caller
    throw new Error('The current time is even, can't do it' + time)  // Throw an error}}try {  // Catch an error
  doThing()
} catch (error) {
  alert(error.message)
}
Copy the code

2. Understanding and use of Promise

2.1 What promises are (important!)

1.

  1. Promise is a new technology (ES6 specification)

  2. Promise is a new solution for asynchronous programming in JS (who’s the old one? Pure callback function)

2.

  1. Syntactically: Promise is a constructor

  2. Functionally: The Promise object encapsulates an asynchronous operation and retrieves its success/failure result

2.2. Why use Promise

1. Specify callback functions in a more flexible way:

Old: Must be specified before starting asynchronous tasks

Promise: Start the asynchronous task => return the Promie object => bind the callback function to the Promise object (which can even be specified after the asynchronous task ends),

That is, you can specify a callback function after an asynchronous task is started or even after the execution of the asynchronous task is complete

2. Support chain call, can solve the problem of callback hell

1) What is callback hell? The result of the asynchronous execution of the external callback is the condition for the execution of the nested callback

2) Callback to hell’s shortcomings? Not easy to read/not easy to handle exceptions

3) Solutions? Promise chain call

4) Ultimate solution? async / await

Example:

// Successful callback function
function successCallback(result{
    console.log("Sound file created successfully: + result);
}
// Failed callback function
function failureCallback(error{
    console.log("Sound file creation failed:" + error);
}

/* 1.1 Encapsulates asynchronous operations with pure callback functions */
createAudioFileAsync(audioSettings, successCallback, failureCallback)  // The specified callback function must be started in the asynchronous task

/* 1.2. Use Promise to encapsulate asynchronous operations */
const promise = createAudioFileAsync(audioSettings);
setTimeout(() = > {  // Even if the callback is specified after the asynchronous task has completed, the result value can be obtained
    promise.then(successCallback, failureCallback);
}, 3000);


/* 2.1. callback hell */
doSomething(function(result{
    // The first asynchronous task successfully starts the second asynchronous task
    doSomethingElse(result, function(newResult{
        // The second asynchronous task successfully starts the third asynchronous task
        doThirdThing(newResult, function(finalResult{
            // The third asynchronous task succeeded
            console.log('Got the final result: ' + finalResult)
        }, failureCallback)
    }, failureCallback)
}, failureCallback)
    
/* 2.2. Use promise's then() chain call to solve callback hell */
doSomething()
    .then(function(result{
    	return doSomethingElse(result)
	})
    .then(function(newResult{
    	return doThirdThing(newResult)
	})
    .then(function(finalResult{
    	console.log('Got the final result: ' + finalResult)
	})
    .catch(failureCallback)
    
/* 2.3. Async /await: the ultimate solution to callback hell */
async function request({
    try {
        const result = await doSomething()
        const newResult = await doSomethingElse(result)
        const finalResult = await doThirdThing(newResult)
        console.log('Got the final result: ' + finalResult)
    } catch (error) {
        failureCallback(error)
    }
}
Copy the code

2.3 Basic use and API of Promise

1. Basic grammar

1) Promise(excutor) constructor

2) Promise.prototype

2. Basic coding process

  1. Create a Promise object (pending state) that specifies the executor function

  2. Start an asynchronous task in an executor function

  3. Different treatments are made according to the results:

1. If the resolved state is resolved, call resolve() and specify the successful value

2. If the reject fails, call Reject () and specify reason. The reject state changes to Rejected

  1. Give a promise a success or failure callback to get a success value or a failure reason

3. State of the promise object

  1. Three states:
  • Pending: State of being undetermined or initialized

  • Resolved: Resolved/successful, state after calling resolve(

  • Rejected: Indicates the reject() state

  1. Two state changes
  • pending ==> resolved

  • pending ==> rejected

  1. The state can only change once!

Illustration:

Example:

// 1) Create a Promise object (pending state) specifying the executor function
const p = new Promise((resolve, reject) = > { // Synchronously executed executor functions
    // 2) Start the asynchronous task in the executor function
    setTimeout(() = > {
        // 3) Do different treatments according to the results
        const time = Date.now()
        // 3.1) If successful, call resolve(), specify successful value, and change to resolved state
        if (time % 2= =1) {
            resolve('Success data' + time)
            console.log('resolve ()')}else { Reject (); reject(); reject(); reject()
            reject('Failed data' + time )
        }
    }, 1000);
})

// 4) Assign a success or failure callback to promise to get a success value or a failure reason
p.then(
    value= > {
        console.log('success', value)
    },
    reason= > {
        console.log('failure', reason)
    }
)
Copy the code
Example: Use Promise + XHR to wrap ajax request functions
function promiseAjax(url) {
    return new Promise((resolve, reject) = > {
        // Use XHR to make asynchronous Ajax requests
        const xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.send()
        xhr.onreadystatechange = () = > {
            // If the request is not completed, end it
            if(xhr.readyState ! = =4) return
            // If successful, call resolve() and specify the successful value
            if (xhr.status >= 200 && xhr.status < 300) {
                resolve(JSON.parse(xhr.response))
            } else {
                // If it fails, call reject() and specify reason for the failure
                reject(new Error('request error status: ' + xhr.status))
            }
        }
    })
}

promiseAjax('https://api.apiopen.top/getJoke? page=1&count=2&type=video')
// promiseAjax('https://api.apiopen.top2/getJoke? page=1&count=2&type=video')
    .then(
        data= > {
            console.log('Request successful', data)
        },
        error= > {
            alert(error.message)
        }
    )
Copy the code

4.API

1.Promise: Promise (excutor) {}

  • Excutor: execute simultaneously (resolve, reject) => {}

  • Resolve function: the function we call when internally defining success value => {}

  • Reject function: The function we call when internal definition fails reason => {}

Note: Excutor immediately synchronizes the callback within the Promise, and the asynchronous operation is performed in the executor

Here’s how to prototype an object:

Prototype. Then (onResolved, onRejected) => {}

  • OnResolved function: Successful callback (value) => {}

  • OnRejected () => {}

Note: Specify a successful callback to get a successful value and a failed callback to get a failed reason

This method returns a new Promise object

Note: onResolved failed to transfer, default value => value

3. Promise. Prototype. Catch method: (onRejected) = > {}

  • OnRejected () => {}

Then () (undefined, onRejected)

Here are the methods of function objects:

4.Promise.resolve: (value) => {}

  • Value: Successful data or promise object

Description: Returns a success/failure promise object

5.Promise. Reject method: (reason) => {}

  • Reason: Indicates the reason for the failure

Description: Returns a failed Promise object

6.Promise. All methods: (promises) => {}

Promises: An array of N promises

Note: Return a new promise, which succeeds only if all promises succeed, or if one fails

7.Promise. Race method: (promises) => {}

Promises: An array of N promises

Note: Return a new promise, and the result state of the first completed promise is the final result state

Example:

new Promise((resolve, reject) = > {
    setTimeout(() = > {
        // resolve(1)
        reject(2)},1000);
}).then(value= > {
    console.log('onResolved()', value)
}/* , reason => { console.log('onRejected()', reason) } */).catch(reason= > {
    console.log('onRejected2()', reason)
})

/* Create a promise object with value 3 */
const p1 = new Promise((resolve, reject) = > {
    setTimeout(() = > {
        resolve(3)},1000);
})
const p2 = Promise.resolve(5)
const p3 = Promise.reject(4)
p1.then(value= > console.log('p1 value', value))
p2.then(value= > console.log('p2 value', value))
p3.catch(reason= > console.log('p3 value', reason))

const p4 = Promise.all([p1, p2, p3])
const p4 = Promise.all([p1, p2])
p4.then(
    values= > console.log('p4 all onResolved()', values), // The order of the values is the same as the order of the Promise array
    reason= > console.log('p4 all onRejected()', reason),
)

const p5 = Promise.race([p1, p3, p2])
p5.then(
    value= > console.log('p5 race onResolved()', value),
    reason= > console.log('p5 race onRejected()', reason),
)
Copy the code

2.4 Important Questions about Promises

1. How to change the state of promise?

(1) Resolve (value): Resolve will change to Resolved if it is pendding

(2) Reject (reason): If it is a reject, it changes to Rejected

(3) Raise exception: If it is Pendding, it will change to Rejected

2. Will multiple success/failure callbacks specified by a promise be called?

This is called whenever a promise changes to the corresponding state

Example:

const p = new Promise((resolve, reject) = > {
  resolve(1) // pending ==> resolved
  // reject(2) // pending ==> rejected
  // throw (rejected); // Throw (rejected) ==
  // resolve(1) // pending ==> resolved
  // reject(2) // Does nothing because the promise state can only change once!
})

p.then(
  value= > console.log('onResolved()', value),
  reason= > console.log('onRejected()', reason)
)
p.then(
  value= > console.log('onResolved2()', value),
  reason= > console.log('onRejected2()', reason)
)
Copy the code

3. Which comes first, changing the promise state or specifying the callback function?

(1) Both are possible. The normal case is to specify the callback and then change the state, but it is also possible to change the state and then specify the callback

(2) How to change the state before specifying the callback?

Resolve ()/reject()

Then ()

(3) When will the data be available?

If the callback is specified first, the callback function will be called when the state changes, and the data will be returned

② If the state is changed first, the callback function will be called when the callback is specified

Example:

/* Specify a callback function, then change the state */
// Start asynchronous tasks in the excutor executor
new Promise((resolve, reject) = > { // Synchronize the callback
  console.log('excutor()')
  // Start an asynchronous task
  setTimeout(() = > {
    resolve(1)  // Pending ==> Resolved value is 1
    console.log('resolve() after changing state ')
    // reject()
  }, 1000)
}).then( // Specify the callback function first, optionally save the callback function
  value= > { // Successful/failed callback functions are executed asynchronously and need to be queued for future execution
    console.log('onResolved()', value)
  }
)
console.log('New Promise() after')

/* change the state and then specify the callback function */
Resolve ()/reject()
new Promise((resolve, reject) = > { // Synchronize the callback
  console.log('excutor()')
  resolve(1)  // Resolved value ==> resolved value = 1
  console.log('resolve() after changing state ')
}).then( // After the specified callback
  value= > {
    console.log('onResolved()', value)
  }
)
console.log('New Promise() after')

//2. Delay calling then() for longer
const p = new Promise((resolve, reject) = > { // Synchronize the callback
  console.log('excutor()')
  // Start an asynchronous task
  setTimeout(() = > {
    resolve(1)  // Pending ==> Resolved value is 1
    console.log('resolve() after changing state ')
    // reject()
  }, 1000)})setTimeout(() = > {
  p.then( // Specify the callback function
    value= > { // Successful/failed callback functions are executed asynchronously and need to be queued for future execution
      console.log('onResolved()', value)
    }
  )
}, 2000);
console.log('New Promise() after')
Copy the code

4. What determines the result state of the new promise returned by promise.then()? (Important!)

(1) Simple expression: the result of the execution of the callback function specified by then()

(2) Detailed expression:

(1) If an exception is raised, the new promise changes to Rejected. Reason is the exception raised

② If any non-PROMISE value is returned, the new promise becomes resolved and value is the returned value

③ If another new promise is returned, the result of that promise becomes the result of the new promise

Example:

new Promise((resolve, reject) = > {
  // resolve(1)
  reject(2)
}).then(
  value= > {
    console.log('onResolved1()', value)
    // throw 4
    // return 3
    // return Promise.resolve(5)
    return Promise.reject(5)},reason= > console.log('onRejected1()', reason),
).then(
  value= > console.log('onResolved2()', value),
  reason= > console.log('onRejected2()', reason),
)
Copy the code

5. How does promise string together multiple action tasks?

(1) Promise’s then() returns a new promise, which can be thought of as a chained call to then()

(2) Chain multiple synchronous/asynchronous tasks through chaining calls to THEN

Example:

new Promise((resolve, reject) = > {
  // Start task 1(asynchronous)
  console.log('Start Task 1(asynchronous)')
  setTimeout(() = > {
    resolve(1)},1000)
}).then(value= > {
  console.log('Task 1 success value is', value)
  // Perform task 2(synchronization)
  console.log('Perform Task 2(Synchronize)')
  return 2
}).then(value= > {
  console.log('Task 2 success value is', value)
  // Perform task 3(asynchronous)
  return new Promise((resolve, reject) = > {
    console.log('Start Task 3(asynchronous)')
    setTimeout(() = > {
      resolve(3)},1000);
  })
}).then(value= > {
  console.log('Task 3 success value is:', value)
})
Copy the code

6. Promise mistakes (important!)

(1) When using promise’s then chain call, you can specify the failed callback at the end,

(2) Any previous error will be passed to the last failed callback

7. Break the Promise chain

(1) When using promise’s then chain call, it breaks in the middle and does not call subsequent callback functions

(2) Method: Return a Pendding Promise object in the callback.

Example:

new Promise((resolve, reject) = > {
  // resolve(1)
  reject(2)
}).then(
  value= > console.log('onResolved1()', value),
  // Unwritten default add the following sentence: throw exception
  // reason => {throw reason}
).then(
  value= > console.log('onResolved2()', value),
  // or reason => promise.reject (reason)
).then(
  value= > console.log('onResolved3()', value),
  // reason => {throw reason}
).catch(
  // Default with successful callback value => value
  reason= > {
    console.log('onRejected1()', reason)
    // throw reason
    return new Promise(() = > {}) // Return a pending promise ==> break the promise chain
}).then(
  value= > console.log('onResolved4()', value),
  reason= > console.log('onRejected2()', reason)
)

// extension: Return an object () => ({a:2})
// Arrow 1 line, function body without parentheses, and only one statement, function body with return by default
Copy the code

3. Customize Promise – the underlying implementation

  1. Define the overall structure

  2. Implementation of the Promise constructor

  3. Implementation of promise.then()/catch()

  4. Implementation of promise.resolve ()/reject()

  5. Promise.all/race() implementation

  6. Implementation of promise.resolveDelay ()/rejectDelay() — Custom new methods (unofficial)

ES5 version implementation:

/* Customize the Promise module */
(function (window) {

  const PENDING = 'pending' // Initial undefined state
  const RESOLVED = 'resolved' // Successful status
  const REJECTED = 'rejected' // Failed state

  /* Promise constructor */
  function Promise(excutor) {
    const self = this // An instance object of Promise
    self.status = PENDING // The state attribute, whose initial value is pending, represents the initial undetermined state
    self.data = undefined // The property used to store the result data. The initial value is undefined
    self.callbacks = [] // {onResolved(){}, onRejected(){}}

    /* Change the state of the promise to success, specifying the success value */
    function resolve(value) {
      // If it is not pending, end it
      if(self.status ! == PENDING)return

      self.status = RESOLVED // Change the status to success
      self.data = value // Save the successful value

      // Call all cached successful callback functions asynchronously
      if (self.callbacks.length > 0) {
        // Start a timer with a delay of 0 and execute all successful callbacks in the timer callback
        setTimeout(() = > {
          self.callbacks.forEach(cbsObj= > {
            cbsObj.onResolved(value)
          })
        })
      }
    }

    /* Change the state of the promise to failed, and specify the failed reason */
    function reject(reason) {
      // If it is not pending, end it
      if(self.status ! == PENDING)return

      self.status = REJECTED // Change the status to failed
      self.data = reason // Save the reason data

      // Call all cached callback functions asynchronously
      if (self.callbacks.length > 0) {
        // Start a timer with a delay of 0 and execute all failed callbacks in the timer callback
        setTimeout(() = > {
          self.callbacks.forEach(cbsObj= > {
            cbsObj.onRejected(reason)
          })
        })
      }
    }

    // Call excutor to start the asynchronous task
    try {
      excutor(resolve, reject)
    } catch (error) { // The executor failed and the current promise becomes a failure
      console.log('-- -- -- -- --)
      reject(error)
    }

  }

  /* The method used to specify the success/failure callback function 1). If the promise is resolved, asynchronously execute the successful callback onResolved 2). If the current promise is Rejected, asynchronously execute the successful callback function onRejected 3). If the current Promise is pending, the save callback returns a new Promise object whose result state is determined by the result of onResolved or onRejected. 2.1). Error ==> rejected; error 2.2). The return value is not PROMISE ==> changed to Resolved, and the result is 2.3). The return value is promise ===> The result (success/failure) of the new promise determined by this promise */
  Promise.prototype.then = function (onResolved, onRejected) {
    const self = this

    onResolved = typeof onResolved === 'function' ? onResolved : value= > value // Pass value down
    onRejected = typeof onRejected === 'function' ? onRejected : reason= > {throw reason} // Pass reason down

    return new Promise((resolve, reject) = > { // When to change its state

      /* 1. Invoke the specified callback function. 2. Update the state that returns promise */ based on the result of the callback execution
      function handle(callback) {
        try {
          const result = callback(self.data)
          if(! (resultinstanceof Promise)) { // 2.2). The return value is resolved
            resolve(result)
          } else { // 2.3). The return value is promise ===> The result of the new promise (success/failure) determined by this promise.
            result.then(
              value= > resolve(value),
              reason= > reject(reason)
            )
            Result. then(resolve, reject)}}catch (error) { // 2.1). Raise error ==> to Rejected
          reject(error)
        }
      }

      if (self.status === RESOLVED) {
        setTimeout(() = > {
          handle(onResolved)
        })
      } else if (self.status === REJECTED) {
        setTimeout(() = > {
          handle(onRejected)
        })
      } else { // PENDING
        self.callbacks.push({
          onResolved(value) { // Object method short {text{}} is equivalent to {text:text{}} object property short {a} is equivalent to {a:a}
            handle(onResolved)
          },
          onRejected(reason) {
            handle(onRejected)
          }
        })
      }
    })
  }


  /* The method used to specify that the failed callback function catch is the syntactic sugar for then */
  Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
  }

  /* The successful promise that returns a specified value can be either a generic value or a promise object */
  Promise.resolve = function (value) {
    return new Promise((resolve, reject) = > {
      // If value is a promise, the result of the return promise is determined by value
      if (value instanceof Promise) {
        value.then(resolve, reject)
      } else { // Value is not a promise, return a successful promise, the successful value is value
        resolve(value)
      }
    })
  }

  /* Return a failed promise for reason */
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) = > {
      reject(reason)
    })
  }

  /* Returns a promise, which succeeds only if all the promises in the array succeed, otherwise fails */
  Promise.all = function (promises) {
    return new Promise((resolve, reject) = > {

      let resolvedCount = 0 // Number of successes - count!
      const values = new Array(promises.length) // Use new Array(promises. Length) rather than [] to save the value of successful promises
      // Iterate over all promises and take their corresponding results
      promises.forEach((p, index) = > {
        p.then(
          value= > {
            resolvedCount++
            values[index] = value // Instead of pushing, store the values in the promise array order
            if (resolvedCount === promises.length) { // It all worked
              resolve(values)
            }
          },
          reason= > reject(reason)
        )
      })
    })
  }

  /* Returns a promise, determined by the first fulfilling promise */
  Promise.race = function (promises) {
    return new Promise((resolve, reject) = > {
      // Iterate over all promises and take their corresponding results
      promises.forEach(p= > {
        // Return a promise whose outcome is determined by the first completion p
        p.then(resolve, reject)
      })
    })
  }


  // The following is an extended exercise official no!
  /* Returns a promise that will succeed (or fail) after a specified amount of time
  Promise.resolveDelay = function (value, time = 0) {
    return new Promise((resolve, reject) = > {
      setTimeout(() = > {
        // If value is a promise, the result of the return promise is determined by value
        if (value instanceof Promise) {
          value.then(resolve, reject)
        } else { // Value is not a promise, return a successful promise, the successful value is value
          resolve(value)
        }
      }, time)
    })
  }

  /* Returns a promise that fails after a specified delay */
  Promise.rejectDelay = function (reason, time = 0) {
    return new Promise((resolve, reject) = > {
      setTimeout(() = > {
        reject(reason)
      }, time)
    })
  }

  // Expose Promise
  window.Promise = Promise}) (window)
Copy the code

ES6 Class edition implementation:

/* Customize the Promise module class version */
(function (window) {

  const PENDING = 'pending' // Initial undefined state
  const RESOLVED = 'resolved' // Successful status
  const REJECTED = 'rejected' // Failed state

  class Promise {
    /* Promise constructor */
    constructor (excutor) {
      const self = this // An instance object of Promise
      self.status = PENDING // The state attribute, whose initial value is pending, represents the initial undetermined state
      self.data = undefined // The property used to store the result data. The initial value is undefined
      self.callbacks = []  // {onResolved(){}, onRejected(){}}

      /* Change the state of the promise to success, specifying the success value */
      function resolve(value) {
        // If it is not pending, end it
        if(self.status ! == PENDING)return

        self.status = RESOLVED // Change the status to success
        self.data = value // Save the successful value

        // Call all cached successful callback functions asynchronously
        if (self.callbacks.length > 0) {
          // Start a timer with a delay of 0 and execute all successful callbacks in the timer callback
          setTimeout(() = > {
            self.callbacks.forEach(cbsObj= > {
              cbsObj.onResolved(value)
            })
          })
        }
      }

      /* Change the state of the promise to failed, and specify the failed reason */
      function reject(reason) {
        // If it is not pending, end it
        if(self.status ! == PENDING)return

        self.status = REJECTED // Change the status to failed
        self.data = reason // Save the reason data

        // Call all cached callback functions asynchronously
        if (self.callbacks.length > 0) {
          // Start a timer with a delay of 0 and execute all failed callbacks in the timer callback
          setTimeout(() = > {
            self.callbacks.forEach(cbsObj= > {
              cbsObj.onRejected(reason)
            })
          })
        }
      }
      
      // Call excutor to start the asynchronous task
      try {
        excutor(resolve, reject)
      } catch (error) { // The executor failed and the current promise becomes a failure
        console.log('-- -- -- -- --)
        reject(error)
      }
      
    }

    /* The method used to specify the success/failure callback function 1). If the promise is resolved, asynchronously execute the successful callback onResolved 2). If the current promise is Rejected, asynchronously execute the successful callback function onRejected 3). If the current Promise is pending, the save callback returns a new Promise object whose result state is determined by the result of onResolved or onRejected. 2.1). Error ==> rejected; error 2.2). The return value is not PROMISE ==> changed to Resolved, and the result is 2.3). The return value is promise ===> The result (success/failure) of the new promise determined by this promise */
    then (onResolved, onRejected) {
      const self = this
      
      onResolved = typeof onResolved==='function' ? onResolved : value= > value // Pass value down
      onRejected = typeof onRejected==='function' ? onRejected : reason= > {throw reason} // Pass reason down

      return new Promise((resolve, reject) = > { // When to change its state

        /* 1. Invoke the specified callback function. 2. Update the state that returns promise */ based on the result of the callback execution
        function handle (callback) {
          try {
            const result = callback(self.data)
            if(! (resultinstanceof Promise)) { // 2.2). The return value is resolved
              resolve(result)
            } else { // 2.3). The return value is promise ===> The result of the new promise (success/failure) determined by this promise.
              result.then(
                value= > resolve(value),
                reason= > reject(reason)
              )
              // result.then(resolve, reject)}}catch (error) { // 2.1). Raise error ==> to Rejected
            reject(error)
          }
        }

        if (self.status===RESOLVED) {
          setTimeout(() = > {
            handle(onResolved)
          })
        } else if (self.status===REJECTED) {
          setTimeout(() = > {
            handle(onRejected)
          })
        } else { // PENDING
          self.callbacks.push({
            onResolved (value) {
              handle(onResolved)
            }, 
            onRejected (reason) {
              handle(onRejected)
            }
          })
        }
      })
    }

    /* The method used to specify that the failed callback function catch is the syntactic sugar for then */
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }

    /* The successful promise that returns a specified value can be either a generic value or a promise object */
    static resolve = function (value) {
      return new Promise((resolve, reject) = > {
        // If value is a promise, the result of the return promise is determined by value
        if (value instanceof Promise) {
          value.then(resolve, reject)
        } else { // Value is not a promise, return a successful promise, the successful value is value
          resolve(value)
        }
      })
    }

      
    /* 
    用来返回一个指定reason的失败的promise
    */
    static reject = function (reason) {
      return new Promise((resolve, reject) = > {
        reject(reason)
      })
    }

    /* Returns a promise, which succeeds only if all the promises in the array succeed, otherwise fails */
    static all = function (promises) {
      return new Promise((resolve, reject) = > {

        let resolvedCount = 0 // The number of successes
        const values = new Array(promises.length) // Hold the value of the successful promise
        // Iterate over all promises and take their corresponding results
        promises.forEach((p, index) = > {
          p.then(
            value= > {
              resolvedCount++
              values[index] = value
              if (resolvedCount === promises.length) { // It all worked
                resolve(values)
              }
            },
            reason= > reject(reason)
          )
        })
      })
    }

    /* Returns a promise, determined by the first fulfilling promise */
    static race = function (promises) {
      return new Promise((resolve, reject) = > {
        // Iterate over all promises and take their corresponding results
        promises.forEach(p= > {
          // Return a promise whose outcome is determined by the first completion p
          p.then(resolve, reject)
        })
      })
    }

    /* Returns a promise that will succeed (or fail) after a specified amount of time
    static resolveDelay = function (value, time) {
      return new Promise((resolve, reject) = > {
        setTimeout(() = > {
          // If value is a promise, the result of the return promise is determined by value
          if (value instanceof Promise) {
            value.then(resolve, reject)
          } else { // Value is not a promise, return a successful promise, the successful value is value
            resolve(value)
          }
        }, time)
      })
    }

    /* Returns a promise that fails after a specified delay */
    static rejectDelay = function (reason, time) {
      return new Promise((resolve, reject) = > {
        setTimeout(() = > {
          reject(reason)
        }, time)
      })
    }
  }

  // Expose the Promise class externally
  window.Promise = Promise}) (window)
Copy the code

Test code:

<! --<script src="./lib/Promise.js"></script> -->
<script src="./lib/Promise_class.js"></script>
/ / test 1
const p = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    // resolve(1)
    // console.log('resolve(after) ')
    
    reject(2)
    reject(3)
  
    console.log('reject ()')},1000)
  // resolve(1)
  // throw 4
})
p.then(
  value= > {console.log('onResolved()', value)},
  reason= > {console.log('onRejected()', reason)}
)
p.then(
  value= > {console.log('onResolved2()', value)},
  reason= > {console.log('onRejected2()', reason)}
)
console.log(p.status)

/ / test 2
new Promise((resolve, reject) = > {
  // resolve(1)
  // setTimeout(() => {
    reject(2)
  // }, 1000);
})
.then(value= > {
  console.log('onResolve()1')
})
.then(
  value= > {console.log('onResolved()2', value)},
  reason= > {
    console.log('onRejected2()', reason)
    // return 3
    // throw 4
    // return new Promise((resolve, reject) =>resolve(5))
    return new Promise((resolve, reject) = >reject(6))
  }
).then(
  value= > {console.log('onResolved3()', value)},
  reason= > {
    console.log('onRejected3()', reason)
    // throw reason
  }
).catch(reason= > {
  console.log('onRejected4()', reason)
}).then(
  value= > {console.log('onResolved5()', value)},
  reason= > {
    console.log('onRejected5()', reason)
  }
)

/ / test 3
const p0 = Promise.resolveDelay(2.100)
const p1 = Promise.resolve(3)
const p2 = Promise.resolve(Promise.resolve(4))
const p3 = Promise.resolve(Promise.reject(5))
const p4 = Promise.reject(6)
const p5 = Promise.rejectDelay(7.2000)

p1.then(value= > {console.log('p1 value', value)})
p2.then(value= > {console.log('p2 value', value)})
p3.catch(reason= > {console.log('p3 reason', reason)})
p4.catch(reason= > {console.log('p4 reason', reason)})

const pRace = Promise.race([p0,p1, p4])
const pRace = Promise.race([p0, p4, p1])
pRace.then(
  value= > console.log('race value', value),
  reason= > console.log('race reason', reason),
)

const pAll = Promise.all([p0,p1, p4])
const pAll = Promise.all([p0,p1])
const pAll = Promise.all([p5,p1])
pAll.then(
  values= > console.log('all values', values),
  reason= > console.log('all reason', reason),
)
Copy the code

4. The async and await

1. The async function

  • The return value of the function is a Promise object

  • The result of the Promise object is determined by the return value executed by the async function

2. Await expression

  • The expression to the right of await is usually a promise object, but it can be any other value

  • If the expression is a Promise object, await returns the promise success value

  • If the expression is another value, return this value directly as await

3. Note:

  • Await must be written in async functions, but async functions can have no await

  • If the await promise fails, an exception is thrown, requiring a try… Catch

4. Why async and await (important!)

  • Simplify the use of Promise objects by specifying callbacks to fetch result data through THEN

  • Call back the ultimate solution to hell

Example:

// Async returns a promise object
async function fn1() {
  // return 1
  // throw 2
  // return Promise.reject(3)
  return Promise.resolve(4)}// const result = fn1()
// console.log(result)

function fn3() {
  // return 3
  // return Promise.resolve(5)
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(6)},2000); })}// Async returns a Promise object in a pending state immediately upon execution
async function fn2() {
  The code after await will be executed in the success callback of then()
  const result = await fn3()
  console.log(result)
}
fn2()
console.log('the fn2 ()')

// Async + await has the same effect as above
function fn4() {
  return fn3().then(result= > {
    console.log(result)
  })
}
// fn4()
// console.log(' after fn4() ')

async function fn5() {
  throw 6
}

async function fn6() {
  try {  / / using a try... Catch to handle the failure of the promise after await
    const result = await fn5()
    console.log('fn6 result=', result)
  } catch (error) {
    console.log('error', error)
  }
}

fn6()
Copy the code

5. Macro versus microqueues (important!)

1. Macro queue: Used to store macro tasks (callbacks) to be executed, such as timer callbacks/DOM event callbacks/Ajax callbacks

2. Microqueue: Used to hold microtasks (callbacks) to be executed, such as promise’s/MutationObserver’s callbacks

3. The two queues will be distinguished when JS is executed

4.JS event loop mechanism – Advanced

1) The JS engine must first perform all the initial synchronization task code

2) Take out all the microtasks one by one before the first macro task is executed

Example:

/* Macro queue: [] macro task micro queue: [] micro task execution result: 3 4 1 5 2 Before preparing to fetch each macro task ready to execute all the micro tasks */
setTimeout(() = > {
  console.log('setTimeout callback()'.1)
  Promise.resolve(5).then(value= > {
    console.log('onResolved3()', value)
  })
}, 0)
setTimeout(() = > {
  console.log('setTimeout callback()'.2)},0)
Promise.resolve(3).then(value= > {
  console.log('onResolved()', value)
})
Promise.resolve(4).then(value= > {
  console.log('onResolved2()', value)
})
Copy the code

Interview question Practice:

/ / 1
setTimeout(() = > {
  console.log(1)},0)
Promise.resolve().then(() = > {
  console.log(2)})Promise.resolve().then(() = > {
  console.log(4)})console.log(3)
// 3 2 4 1

/ / 2
setTimeout(() = > {
  console.log(1)},0)
new Promise((resolve) = > {
  console.log(2)
  resolve()
}).then(() = > {
  console.log(3)
}).then(() = > {
  console.log(4)})console.log(5)
// 2 5 3 4 1
/* macro: [] micro: [] */

/ / 3
const first = () = > (new Promise((resolve, reject) = > {
  console.log(3)
  let p = new Promise((resolve, reject) = > {
    console.log(7)
    setTimeout(() = > {
      console.log(5)
      resolve(6)},0)
    resolve(1)
  })
  resolve(2)
  p.then((arg) = > {
    console.log(arg)
  })

}))

first().then((arg) = > {
  console.log(arg)
})
console.log(4)
// 3 7 4 1 2 5
/* macro: [] micro: [] */

/ / 4
setTimeout(() = > {
  console.log("0")},0)
new Promise((resolve, reject) = > {
  console.log("1")
  resolve()
}).then(() = > {
  console.log("2")
  new Promise((resolve, reject) = > {
    console.log("3")
    resolve()
  }).then(() = > {
    console.log("4")
  }).then(() = > {
    console.log("5")
  })
}).then(() = > {
  console.log("6")})new Promise((resolve, reject) = > {
  console.log("Seven")
  resolve()
}).then(() = > {
  console.log("8")})/* 1 7 2 3 4 6 50 macro: [] micro: [] */

/ / 5
async function async1() {
  console.log('async1 start')
  await async2() // async2().then(() => {})
  console.log('async1 end')}async function async2() {
  console.log('async2')}console.log('script start')

setTimeout(() = > {
  console.log('setTimeout')},0)

async1()

new Promise(function (resolve) {
  console.log('promise1')
  resolve()
}).then(function () {
  console.log('promise2')})console.log('script end')
/* macro: [] micro: [] */
Script start async1 start async2 promise1 script end async1 end promise2 setTimeout */
Copy the code