Learning notes of JavaScript advanced programming | 11.2. About

Time:2021-9-25

followFront end Xiaoao, read more original technical articles

time limit

  • Expectation is a substitute for non-existent results. It is a mechanism for asynchronous program execution

Relevant code →

Promises / A + specification

  • ES6 addedPromiseType, which has become the dominant asynchronous programming mechanism, which is supported by all modern browsers

Contractual basis

  • PromiseType passnewOperator instantiation, need to pass inExecutor functionAs a parameter
//Let P = new promise() // typeerror: promise resolver undefined is not a function. You must provide an actuator function as a parameter
let p = new Promise(() => {})
setTimeout(console.log, 0, p) // Promise { <pending> }

Contract state machine

  • An appointment is a stateful object:

    • undeterminedpendingexpressNot started or in progress。 The initial state can be settled as cash or reject,Irreversibility after cashing
    • cashfullfilled(or settlement)resolved)Indicates successful completion
    • refuserejectedIndicates that it did not complete successfully
  • The status of the appointment isprivate, which will act asynchronouslyencapsulationget upquarantineExternal code,NoRead or modified by external JS code

Solution value, rejection reason and contract use case

  • The scheduled state machine can provide useful information. Suppose it sends an HTTP request to the server:

    • Return the status code in the range of 200-299 to change the status of the promise to “cash”, and the promiseinsidereceivedprivateofJSONString. The default value is undefined
    • Returning a status code that is not in the range of 200-299 will switch the appointment status to “reject”insidereceivedprivateofErrorObject (containing error messages), the default value is undefined

Control period state by executing function

  • The status of the appointment isprivateYes, only inActuator functionMedium completionInternal operation
  • The actuator function is responsible forAsynchronous behavior during initializationandControl state transition

    • adoptresolve()andreject()Two function parameters control the state transition
    • resolve()Will switch the state toexchangereject()Will switch the state torefuseandThrow error
let p1 = new Promise((resolve, reject) => resolve())
setTimeout(console.log, 0, p1) // Promise {<fulfilled>: undefined}

let p2 = new Promise((resolve, reject) => reject())
setTimeout(console.log, 0, p2) // Promise {<rejected>: undefined}
// Uncaught (in promise)
  • The executor function is the initialization program of the contract, which issynchronizationExecutive
new Promise(() => setTimeout(console.log, 0, 'executor'))
setTimeout(console.log, 0, 'promise initialized')
/* 
  'executor', print first
  'promise initialized', print after
*/
  • Can addsetTimeoutPostpone the switching state of the actuator function
let p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000)
})
SetTimeout (console. Log, 0, P3) // promise {< pending >}. When printing instance P3, the internal callback will not be executed
  • resolve()andreject()No matter which is called, the state transition is completeIrrevocable, continue to modify the statusSilent failure
let p4 = new Promise((resolve, reject) => {
  resolve()
  Reject() // silence failed
})
setTimeout(console.log, 0, p4) // Promise {<fulfilled>: undefined}
  • In order to avoid the appointment card in the pending state, you canAdd timed exitFunction, after setting a certain length of time, reject the callback of the appointment in any case
let p5 = new Promise((resolve, reject) => {
  SetTimeout (reject, 10000) // 10 seconds after calling reject ()
})
setTimeout(console.log, 0, p5) // Promise   {< pending >}, do not call resolve() within 10 seconds
setTimeout(console.log, 11000, p5) // Promise   {< rejected >: undefined}, call reject() after 10 seconds
// Uncaught (in promise)

Promise.resolve()

  • callPromise.resolve()Method, yesinstantiation OneResolvedtime limit
let p6 = new Promise((resolve, reject) => {
  resolve()
})
console.log(p6) // Promise {<fulfilled>: undefined}
let p7 = Promise.resolve()
console.log(p7) // Promise {<fulfilled>: undefined}
  • Pass toPromise.resolve()ofFirst parameterThe value of the approximate period to be resolved
setTimeout(console.log, 0, Promise.resolve()) // Promise {<fulfilled>: undefined}
setTimeout(console.log, 0, Promise.resolve(3)) // Promise {<fulfilled>: 3}
setTimeout(console.log, 0, Promise.resolve(4, 5, 6)) // Promise   {< fully >: 4}, only the first parameter is taken
  • Promise.resolve()It’s aidempotentMethod, if passed inThe parameter is a period, which behaves like aEmpty packaging
let p8 = Promise.resolve(7)
setTimeout(console.log, 0, Promise.resolve(p8)) // Promise { 7 }
setTimeout(console.log, 0, p8 === Promise.resolve(p8)) // true
setTimeout(console.log, 0, p8 === Promise.resolve(Promise.resolve(p8))) // true
  • This idempotency willretainAfferent periodstate
Let P9 = new promise (() = > {}) // pending status
setTimeout(console.log, 0, p9) // Promise { <pending> }
setTimeout(console.log, 0, Promise.resolve(p9)) // Promise { <pending> }
setTimeout(console.log, 0, Promise.resolve(Promise.resolve(p9))) // Promise { <pending> }
  • This method can packageAny non approximate value(including error objects) andConversion to settlement periodTherefore, it may lead to unexpected behavior
let p10 = Promise.resolve(new Error('foo'))
setTimeout(console.log, 0, p10) // Promise {<fulfilled>: Error: foo

Promise.reject()

  • AndPromise.resolve()be similar,Promise.reject()sureinstantiation OneRejectedPeriod about andThrow an asynchronous error

    • This errorNoadopttry/catchCapture, which can only be captured through the reject handler
let p11 = new Promise((resolve, reject) => {
  reject()
})
console.log(p11) // Promise {<rejected>: undefined}
// Uncaught (in promise)

let p12 = Promise.reject()
console.log(p12) // Promise {<rejected>: undefined}
// Uncaught (in promise)
  • Pass toPromise.resolve()ofFirst parameterThis parameter is also used as the reason for rejecting the appointmentPassed to subsequent reject handlers
let p13 = Promise.reject(3)
setTimeout(console.log, 0, p13) // Promise { <rejected> 3 }
P13. Then (null, (ERR) = > setTimeout (console. Log, 0, ERR)) // 3. Pass the parameter to the subsequent rejection handler
  • Promise.reject()Not idempotent (andPromise.resolve()If the parameter appointment object is different, the appointment will become the rejection reason returned
setTimeout(console.log, 0, Promise.reject(Promise.resolve())) // Promise {<rejected>: Promise}

Duality of synchronous / asynchronous execution

  • Due to contractualAsynchronous Characteristics, although it is a synchronous object (which can be used in synchronous execution mode), it is also the medium of asynchronous execution mode

    • The code for the synchronization thread failed to capture the rejected appointment, the error of rejecting the appointment will passBrowser asynchronous message queuingTo handle
    • Once the code starts executing in asynchronous mode, the only way to interact with it isUse asynchronous structure, spot approx
try {
  Throw new error ('foo ') // the synchronization thread throws an error
} catch (error) {
  Console.log (error +'1 ') // error: foo1. The synchronization thread captures an error
}

try {
  Promise. Reject ('bar ') // the service life of the synchronization thread is about
} catch (error) {
  Console.log (error +'2 ') // the synchronization thread cannot catch the rejected period
}
// Promise   {< rejected >: "bar"}, the browser asynchronous message queue captures the rejected period
// Uncaught (in promise) bar

Example method of contract

  • These methods can access the data returned by asynchronous operations and process the results of success and failure

Implement thenable interface

  • In the asynchronous structure exposed by ECMAScript, any object has onethen()Method, which is considered to be implementedthenableInterface
class MyThenable {
  //The simplest class that implements the thenable interface
  then() {}
}

Promise.prototype.then()

  • Promise.prototype.then()For aboutAdd handler, receive2 optional handler parametersonResolvedandonRejected

    • onResolvedWill enter during the periodcashExecute on status
    • onRejectedWill enter during the periodrefuseExecute on status
function onResolved(id) {
  setTimeout(console.log, 0, id, 'resolved')
}
function onRejected(id) {
  setTimeout(console.log, 0, id, 'rejected')
}
let p14 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000)
})
let p15 = new Promise((resolve, reject) => {
  setTimeout(reject, 3000)
})

p14.then(
  () => {
    Onresolved ('p14 ') /' P14 resolved '(after 3 seconds)
  },
  () => {
    onRejected('p14')
  }
)
p15.then(
  () => {
    onResolved('p15')
  },
  () => {
    Onrejected ('p15 ') /' p15 rejected '(after 3 seconds)
  }
)
  • Pass tothen()Any parameter of non function type will be silently ignored (not recommended), if onlyonResolvedoronRejected, usually passed in at another parameter locationnullorundefined
P14. Then ('gobbeltygook ') // the parameter is not an object and is ignored silently
P14. Then (() = > onresolved ('p14 ') //' P14 resolved '(after 3 seconds), no onrejected
P15. Then (null, () = > onrejected ('p15 ') //' p15 rejected '(after 3 seconds), no onresolved
  • Promise.prototype.then()Return aNew appointment examples, the instance is based ononResolvedHandler(Promise.resolved()Build the return value of (wrapper)

    • ifThis handler was not provided, packagingthe previousValue after contract settlement (transfer of parent contract)
    • If a handler is provided, butThere are no return statements displayed, the default return value is wrappedundefined
    • If a handler is provided, andThere are displayed return values, packagingThis value
    • If a handler is provided, andReturn period, packagingReturn period
    • If a handler is provided, andThrow exception, packagingRejected appointment
    • If a handler is provided, andReturn error value, thenError objectPacked in oneSettlement periodMedium (not rejected)
let p16 = Promise.resolve('foo')

Let result1 = p16. Then() // no handler provided
setTimeout(console.log, 0, result1) // Promise   {< fulfilled >:'foo '}, the value after the settlement of the last period of packaging

Let result2 = p16. Then (() = > undefined) // return statements not displayed by the handler
Let result3 = p16. Then (() = > {}) // return statement not displayed by the handler
Let result4 = p16. Then (() = > promise. Resolve()) // the handler does not display the return statement
setTimeout(console.log, 0, result2) // Promise   {< fully >: undefined}, the default return value of packaging is undefined
setTimeout(console.log, 0, result3) // Promise   {< fully >: undefined}, the default return value of packaging is undefined
setTimeout(console.log, 0, result4) // Promise   {< fully >: undefined}, the default return value of packaging is undefined

Let Result5 = p16. Then (() = > 'bar') // the handler has the displayed return value
Let result6 = p16. Then (() = > promise. Resolve ('bar ')) // the handler has the displayed return value
setTimeout(console.log, 0, result5) // Promise   {< fully >:'bar '}, wrap this value
setTimeout(console.log, 0, result6) // Promise   {< fully >:'bar '}, wrap this value

Let result7 = p16. Then (() = > New Promise (() = > {})) // the handler returns a pending promise
Let result8 = p16. Then (() = > promise. Reject ('bar ')) // the handler returns a rejected period
// Uncaught (in promise) bar
setTimeout(console.log, 0, result7) // Promise   {< pending >}, packaging return period
setTimeout(console.log, 0, result8) // Promise   {< rejected >:'bar '}, the return period of packaging is about

let result9 = p16.then(() => {
  Throw 'Baz' // the handler throws an exception
})
// Uncaught (in promise) baz
setTimeout(console.log, 0, result9) // Promise   {< rejected >:'baz '}, date of package rejection

Let result10 = p16. Then (() = > error ('qux ')) // the handler returns an error value
setTimeout(console.log, 0, result10) // Promise   {< fulfilled >: error: qux}, wrap the error object in a resolution period
  • AndonResolvedSame,onRejectedWhen a handler is used as a parameter, its returned value is alsoPromise.resolve()Packaging, returnNew appointment examples
let p17 = Promise.reject('foo')

Let result11 = p17. Then() // no handler provided
// Uncaught (in promise) foo
setTimeout(console.log, 0, result11) // Promise   {< rejected >:'foo '}, the value after the settlement of the last period of packaging

Let result12 = p17. Then (null, () = > undefined) // the handler does not display the return statement
Let result13 = p17. Then (null, () = > {}) // return statement not displayed by the handler
Let result14 = p17. Then (null, () = > promise. Resolve()) // return statements not displayed by the handler
setTimeout(console.log, 0, result12) // Promise   {< fully >: undefined}, the default return value of packaging is undefined
setTimeout(console.log, 0, result13) // Promise   {< fully >: undefined}, the default return value of packaging is undefined
setTimeout(console.log, 0, result14) // Promise   {< fully >: undefined}, the default return value of packaging is undefined

Let result15 = p17. Then (null, () = > 'bar') // the handler has a displayed return value
Let result16 = p17. Then (null, () = > promise. Resolve ('bar ') // the handler has the displayed return value
setTimeout(console.log, 0, result15) // Promise   {< fully >:'bar '}, wrap this value
setTimeout(console.log, 0, result16) // Promise   {< fully >:'bar '}, wrap this value

Let result17 = p17. Then (null, () = > New Promise (() = > {})) // the handler returns a pending period
Let result18 = p17. Then (null, () = > promise. Reject ('bar ') // the handler returns a rejected period
// Uncaught (in promise) bar
setTimeout(console.log, 0, result17) // Promise   {< pending >}, packaging return period
setTimeout(console.log, 0, result18) // Promise   {< rejected >:'bar '}, the return period of packaging is about

let result19 = p17.then(null, () => {
  Throw 'Baz' // the handler throws an exception
})
// Uncaught (in promise) baz
setTimeout(console.log, 0, result19) // Promise   {< rejected >:'baz '}, date of package rejection

Let result20 = p17. Then (null, () = > error ('qux ')) // the handler returns an error value
setTimeout(console.log, 0, result20) // Promise   {< fulfilled >: error: qux}, wrap the error object in a resolution period

Promise.prototype.catch()

  • Promise.prototype.catch()For aboutAdd reject handler, receive1 optional handler parameteronRejected

    • This method is equivalent to callingPromise.prototypr.then(null, onRejected)
    • The method also returnsNew appointment examples, its behavior andPromise.prototype.then()ofonRejetedSame as the handler
let p18 = Promise.reject()
let onRejected2 = function () {
  setTimeout(console.log, 0, 'reject')
}
p18.then(null, onRejected2) // 'reject'
P18. Catch (onrejected2) // 'reject'. The two methods of adding rejection handlers are the same

Promise.prototype.finally()

  • Promise.prototype.finally()For aboutAdd onfinanally handler, receive1 optional handler parameteronFinally

    • Regardless of the conversion periodsolvestillrefuseStatus,onFinallyprocessing programWill be implemented, but it cannot know the status of the appointment
    • This method is mainly used forAdd cleanup code
let p19 = Promise.resolve()
let p20 = Promise.reject()
let onFinally = function () {
  setTimeout(console.log, 0, 'Finally')
}
p19.finally(onFinally) // 'Finally'
p20.finally(onFinally) // 'Finally'
  • Promise.prototype.finally()Return aNew appointment examples, which are packed in the following casesTransmission of parent contract

    • No handler provided
    • A handler was provided, but no return statement was displayed
    • A handler is provided with a displayed return value
    • The handler returns a resolution period
    • The handler returned an error value
let p21 = Promise.resolve('foo')

Let result23 = p21. Finally() // no handler provided
Let result24 = p21. Finally (() = > undefined) // a handler is provided, but no return statement is displayed
Let result25 = p21. Finally (() = > {}) // the handler is provided, but there is no return statement displayed
Let result26 = p21. Finally (() = > promise. Resolve()) // a handler is provided, but no return statement is displayed
Let result27 = p21. Finally (() = > 'bar') // the handler is provided and the return value is displayed
Let result28 = p21. Finally (() = > promise. Resolve ('bar ')) // the handler returns a resolution period
Let result29 = p21. Finally (() = > error ('qux ')) // the handler returns an error value
setTimeout(console.log, 0, result23) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result24) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result25) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result26) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result27) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result28) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
setTimeout(console.log, 0, result29) // Promise   {< fulfilled >:'foo '}, the delivery of packaging parent date
  • ifonFinallyHandler returnPending or rejected appointmentsorThrow error, the return value is wrappedCorresponding period(throw out the period of wrong packaging rejection)
Let result30 = p21. Finally (() = > New Promise (() = > {})) // the handler returns a pending promise
Let result31 = p21. Finally (() = > promise. Reject()) // the handler returns a rejected period
// Uncaught (in promise) undefined
let result32 = p21.finally(() => {
  Throw 'Baz' // the handler throws an error
})
// Uncaught (in promise) baz
setTimeout(console.log, 0, result30) // Promise   {< pending >}, return the corresponding period
setTimeout(console.log, 0, result31) // Promise   {< rejected >: undefined}, return the corresponding period
setTimeout(console.log, 0, result32) // Promise   {< rejected >:'baz '}, return the corresponding period
  • onFinallyHandler returnAfter the pending contract is resolved, the new appointment instance is still transferred to the initial appointment
let p22 = Promise.resolve('foo')
let p23 = p22.finally(
  () = > New Promise ((resolve, reject) = > setTimeout (() = > resolve ('bar '), 100)) // the handler returns a pending period (to be resolved in 100 milliseconds)
)
setTimeout(console.log, 0, p23) // Promise   {< pending >}, return the corresponding period
setTimeout(() => setTimeout(console.log, 0, p23), 200) // Promise   {< fulfilled >: "foo"}, the pending period (after 200ms) has been resolved

Non reentrant dating method

  • Date entrySettled (resolved / rejected)State, associated with that stateThe handler does not execute immediately, post handlerSynchronization codeBefore itExecute first, this property is calledNon reentrant
Let p24 = promise. Resolve() // the settlement date has been settled
P24. Then (() = > console. Log ('onresolved handler ') // onresolved handler related to contract status
Console.log ('then() returns') // synchronization code after the handler
/* 
  'then () Returns', the synchronization code after the handler is executed first
  'onResolved handler'
*/
  • Even if the period is aboutAfter handlerjustChange status (resolve / reject), the handler still behavesNon reentrantcharacteristic
Let synchroousresolve // global method: appointment status
let p25 = new Promise((resolve) => {
  synchronousResolve = function () {
    console.log('1: invoking resolve()')
    Resolve() // appointment status changes
    console.log('2: resolve() returns')
  }
})
P25. Then (() = > console. Log ('4: then () handler executes') // onresolved handler related to contract status
Synchroousresolve() // synchronization code after the handler: change of appointment status
Console. Log ('3: synchroousresolve() returns') // synchronization code after the handler
/* 
  '1: invoking resolve()'
  '2: resolve() returns'
  '3: synchronousResolve() returns'
  '4: then() handler executes'
*/
  • Non reentrant properties apply toonResolvedonRejectedcatch()finally()processing program
let p26 = Promise.resolve()
p26.then(() => console.log('p26.then() onResolved'))
console.log('p26.then() returns')

let p27 = Promise.reject()
p27.then(null, () => console.log('p27.then() onRejected'))
console.log('p27.then() returns')

let p28 = Promise.reject()
p28.catch(() => console.log('p28.catch() onRejected'))
console.log('p28.catch() returns')

let p29 = Promise.resolve()
p26.finally(() => console.log('p29.finally() onFinally'))
console.log('p29.finally() returns')
/* 
  'p26.then() returns'
  'p27.then() returns'
  'p28.catch() returns'
  'p29.finally() returns'
  'p26.then() onResolved'
  'p27.then() onRejected'
  'p28.catch() onRejected'
  'p29.finally() onFinally'
*/

Execution order of adjacent handlers

  • If the appointment is addedMultiple handlers, when the status changes in the current period, the processing procedure shall be followedAdd orderSequential execution

    • then()catch()finally()This is true for all added handlers
let p30 = Promise.resolve()
let p31 = Promise.reject()

p30.then(() => setTimeout(console.log, 0, 1))
p30.then(() => setTimeout(console.log, 0, 2))

p31.then(null, () => setTimeout(console.log, 0, 3))
p31.then(null, () => setTimeout(console.log, 0, 4))

p31.catch(() => setTimeout(console.log, 0, 5))
p31.catch(() => setTimeout(console.log, 0, 6))

p30.finally(() => setTimeout(console.log, 0, 7))
p30.finally(() => setTimeout(console.log, 0, 8))
/* 
  1
  2
  3
  4
  5
  6
  7
  8
*/

Pass resolution value and reject reason

  • Date entrySettled (resolved / rejected)After the status is, the handler is provided withSolution value (cashout)orReasons for rejection (rejection)

    • stayExecution functionIn, the solution value and rejection reason are used asresolve()andreject()ofFirst parameter, pass toonResolvedandonRejectedHandler (as itsUnique parameter
    • stayPromise.resolve()andPromise.reject()When called, the received resolution value and rejection reason are also passed back to the handler as itsUnique parameter
Let P32 = new promise ((resolve, reject) = > resolve ('foo ')) // execute the function
p32.then((value) => console.log(value)) // 'foo'
Let P33 = new promise ((resolve, reject) = > reject ('bar ')) // execute the function
p33.catch((reason) => console.log(reason)) // 'bar'

Let p34 = promise. Resolve ('foo ') // in promise. Resolve()
p34.then((value) => console.log(value)) // 'foo'
Let p35 = promise. Reject ('bar ') // in promise. Reject()
p35.catch((reason) => console.log(reason)) // 'bar'

Rejection period and rejection error handling

  • In due courseExecution functionorprocessing programThrowing an error in will result in rejection,Error objectbecomeReasons for refusal
Let p36 = new promise ((resolve, reject) = > reject (error ('foo ')) // throw an error in the execution function
let p37 = new Promise((resolve, reject) => {
  Throw error ('foo ') // an error is thrown in the execution function
})
let p38 = Promise.resolve().then(() => {
  Throw error ('foo ') // an error is thrown in the handler
})
Let P39 = promise. Reject (error ('foo ')) // throw an error in the rejected contract
setTimeout(console.log, 0, p36) // Promise {<rejected>: Error: foo
setTimeout(console.log, 0, p37) // Promise {<rejected>: Error: foo
setTimeout(console.log, 0, p38) // Promise {<rejected>: Error: foo
setTimeout(console.log, 0, p39) // Promise {<rejected>: Error: foo
  • Can beAny reasonRejection, includingundefined, but bestUnified use of error objects, the error object allows the browser to captureStack trace information
  • If the above rejection period is about, four uncapped errors will be thrown in the browser:

    • Promise.resolve().then()The error occurred last because it needs to be at run timeAdd handler(i.e. create another new period before capture)
/*The above rejection period appointment throws four uncapped errors: stack tracking information
  Uncaught (in promise) Error: foo
  at <anonymous>:1:51
  at new Promise (<anonymous>)
  at <anonymous>:1:11
  (anonymous)    @    VM1402:1
  (anonymous)    @    VM1402:1

  Uncaught (in promise) Error: foo
  at <anonymous>:3:9
  at new Promise (<anonymous>)
  at <anonymous>:2:11
  (anonymous)    @    VM1402:3
  (anonymous)    @    VM1402:2

  Uncaught (in promise) Error: foo
  at <anonymous>:8:26
  (anonymous)    @    VM1402:8

  Uncaught (in promise) Error: foo
  at <anonymous>:6:9
  (anonymous)    @    VM1402:6
  Promise.then (async)        
  (anonymous)    @    VM1402:5
*/
  • Asynchronous errorThe mechanism is different from synchronization:

    • Synchronization code passedthrow()When keyword throws an error, it stops executing any subsequent commands
    • When an error is thrown in the contract, the synchronization instruction is not blocked, and itserrorIt can only be done asynchronouslyonRejectedprocessing programcapture
Throw error ('foo ') // the synchronization code throws an error (which can be caught in try / catch)
Console.log ('bar ') // no subsequent instructions will be executed
//Uncaught error: foo, browser message queue

Promise. Reject (error ('foo ')) // an error is thrown during the appointment (not captured in try / catch)
Console.log ('bar ') //'bar', the synchronization instruction continues to execute
//Uncaught (in promise) error: foo, browser message queue

Promise.reject(Error('foo')).catch((e) => {
  Console. Log (E) // 'error: foo', captured in the contract
})
  • Execution functionError inBefore settling or rejecting the contract, still availabletry/catchcapture
let p40 = new Promise((resolve, reject) => {
  try {
    throw Error('foo')
  } catch (error) {}
  resolve('bar')
})
setTimeout(console.log, 0, p40) // Promise {<fulfilled>: 'bar'}
  • then()andcatch()ofonRejectedHandlers are semantically related totry/catchThe same (isolate the error after capturing it, without affecting the normal logic), soonRejectAfter the handler catches an asynchronous errorReturns a resolved appointment
console.log('begin synchronous execution')
try {
  Throw error ('foo ') // a synchronization error is thrown
} catch (error) {
  Console.log ('cause error ', error) // capture synchronization errors
}
console.log('continue synchronous execution')
/*
  'begin synchronous execution'
  'caught error Error: foo'
  'continue synchronous execution'
*/

new Promise((resolve, reject) => {
  console.log('begin synchronous execution')
  Reject (error ('bar ') // an asynchronous error is thrown
})
  .catch((e) => {
    Console.log ('cause error ', e) // capturing asynchronous errors
  })
  .then(() => {
    console.log('continue synchronous execution')
  })
/*

Periodic linkage and periodic synthesis

  • Multiple periods together can form powerful code logic:Date chain (splicing)AndPeriodic synthesis (combination)

Periodic linkage

  • Instance method for each period(then()catch()finally())All return new contract instances, and multiple contracts can be formed by concatenating callsPeriodic linkage
let p41 = new Promise((resolve, reject) => {
  console.log('first')
  resolve()
})
p41
  .then(() => console.log('second'))
  .then(() => console.log('third'))
  .then(() => console.log('fourth'))
/* 
  'first'
  'second'
  'third'
  'fourth'
*/
  • If you want toSerialize asynchronous tasks, need to letEach actuator returns a periodic instance
let p42 = new Promise((resolve, reject) => {
  console.log('p42 first')
  setTimeout(resolve, 1000)
})
p42
  .then(
    () =>
      //Example of actuator return period
      new Promise((resolve, reject) => {
        console.log('p42 second')
        setTimeout(resolve, 1000)
      })
  )
  .then(
    () =>
      //Example of actuator return period
      new Promise((resolve, reject) => {
        console.log('p42 third')
        setTimeout(resolve, 1000)
      })
  )
  .then(
    () =>
      //Example of actuator return period
      new Promise((resolve, reject) => {
        console.log('p42 fourth')
        setTimeout(resolve, 1000)
      })
  )
/* 
  'p42 first' (after 1 second)
  'p42 second' (after 2 seconds)
  'p42 third' (after 3 seconds)
  'p42 fourth' (after 4 seconds)
*/
  • The generation period can be about the same codeencapsulationTo a factory function
function delayedResolve(str) {
  return new Promise((resolve, reject) => {
    console.log(str)
    setTimeout(resolve, 1000)
  })
}
delayedResolve('p42 first')
  .then(() => delayedResolve('p42 second'))
  .then(() => delayedResolve('p42 third'))
  .then(() => delayedResolve('p42 fourth'))
/* 
  'p42 first' (after 1 second)
  'p42 second' (after 2 seconds)
  'p42 third' (after 3 seconds)
  'p42 fourth' (after 4 seconds)
*/
  • Futures chain can be effectiveResolve callback hellProblem, if the above code is not used, the date is as follows
function delayedNotPromise(str, callback = null) {
  setTimeout(() => {
    console.log(str)
    callback && callback()
  }, 1000)
}
delayedNotPromise('p42 first', () => {
  delayedNotPromise('p42 second', () => {
    delayedNotPromise('p42 third', () => {
      delayedNotPromise('p42 fourth', () => {})
    })
  })
})
/* 
  'p42 first' (after 1 second)
  'p42 second' (after 2 seconds)
  'p42 third' (after 3 seconds)
  'p42 fourth' (after 4 seconds)
*/
  • then()catch()finally()New appointment instances are returned, and appointment chaining can be performed arbitrarily
let p43 = new Promise((resolve, reject) => {
  console.log('p43')
  reject()
})
p43
  .catch(() => console.log('p43 catch'))
  .then(() => console.log('p43 then'))
  .finally(() => console.log('p43 finally'))
/* 
  'p43'
  'p43 catch'
  'p43 then'
  'p43 finally'
*/

Period reduction diagram

  • A contract can have any number of handlers, and a contract chain can be builtDirected acyclic graph
- A
  - B
    - D
    - E
  - C
    - F
    - G
let A = new Promise((resolve, reject) => {
  console.log('A')
  resolve()
})
let B = A.then(() => console.log('B'))
let C = A.then(() => console.log('C'))
B.then(() => console.log('D'))
B.then(() => console.log('E'))
C.then(() => console.log('F'))
C.then(() => console.log('F'))
/* 
  'A'
  'B'
  'C'
  'D'
  'E'
  'F'
*/

Promise. All() and promise. Race()

  • Promise.all()Receive oneIteratable object(required), return oneNew periodThe appointment it created onAfter a group of problems are solvedRe solve

    • Elements in iteratable objectsPromise.resolve()The conversion period is about
    • An empty iteration object is equivalent toPromise.resolve()
Promise. All ([promise. Resolve()), promise. Resolve()] // receive a group of iteratable objects
Promise. All ([3, 4]) // elements in the iteratable object can be converted through promise. Resolve(), lasting for about
Promise. All ([]) // empty iteration object is equivalent to promise. Resolve()
Promise. All() // typeerror: undefined is not Iterable (cannot read property symbol (symbol. Iterator)), parameter is required
  • Promise.all()The synthetic period will only be aboutAfter each inclusion period is resolvedJust solve
let p44 = Promise.all([
  Promise.resolve(),
  new Promise((resolve, reject) => setTimeout(resolve, 1000)),
])
p44.then(() => setTimeout(console.log, 0, 'all() resolved!')) // 'all() resolved!' (after 1 second, it is not 0 second, which needs to be solved before the included period)
  • If there is one included contract to be determined, the contract to be determined will be synthesized, and the rejection is the same (rejection takes precedence over determination)
Let P45 = promise.all ([New Promise (() = > {}), promise. Resolve()]) // the included period is about to be determined
setTimeout(console.log, 0, p45) // Promise   {< pending >}, synthesize the pending period
Let P46 = promise. All ([New Promise (() = > {}), promise. Reject()]) // there are some rejected (or undetermined) dates
// Uncaught (in promise) undefined
setTimeout(console.log, 0, p46) // Promise   {< rejected >: undefined}, the period of synthesis rejection
  • If all the contained period constraints are successfully resolved, the resolved period constraints are synthesized, and the resolution value is an array of all the resolution values containing the period constraints (in iterator order)
let p47 = Promise.all([
  Promise.resolve(1),
  Promise.resolve(),
  Promise.resolve(3),
]) // all included appointments are resolved
setTimeout(console.log, 0, p47) // Promise {<fulfilled>: [1, undefined, 3]}
  • If a date is refused,firstRejected dates use their own reasons as a reasonReasons for refusal of composition period(the subsequent reasons will no longer affect the reasons for refusal of the composition period), butNot affectRejection of subsequent appointments
let p48 = Promise.all([
  Promise. Reject (3), // the first rejected appointment. The reason for rejection is 3
  New promise ((resolve, reject) = > setTimeout (reject, 1000, 4)), // the second period of rejection. The reason for rejection is 4
])
// Uncaught (in promise) 3
setTimeout(console.log, 0, p48) // Promise   {< rejected >: 3}, the first reason for rejection is the reason for rejection of the contract during the synthesis period
P48. Catch ((reason) = > setTimeout (console. Log, 2000, reason)) // 3. The first reason for rejection is used as the reason for rejection of the composition period, but the browser will not display an unhandled error (uncaught (in promise) 3)
  • Promise.race()AndPromise.all()Similarly, receive aIteratable object(required), in the package collectionSettle first (resolve or reject)The appointment resolves the value or reason for rejection and returnsNew period

    • Elements in iteratable objectsPromise.resolve()The conversion period is about
    • An empty iteration object is equivalent toPromise.resolve()
    • The iterative order determines the settling order
    • The first date to refuse takes his own reason as a reasonReasons for refusal of composition period, butIt does not affect the rejection of * * subsequent appointments
Promise. Race ([promise. Resolve()), promise. Resolve()] // receive a group of iteratable objects
Promise. Race ([3, 4]) // elements in the iteratable object can be converted through promise. Resolve(), lasting for about
Promise. Race ([]) // empty iteration object is equivalent to promise. Resolve()
//Promise. All() // typeerror: undefined is not Iterable (cannot read property symbol (symbol. Iterator)), parameter is required

let p49 = Promise.race([
  Promise.resolve(3),
  new Promise((resolve, reject) => setTimeout(reject, 1000)),
])
setTimeout(console.log, 0, p49) // Promise   {< fully >: 3}, the solution occurs first, and the rejection after timeout is ignored

let p50 = Promise.race([
  Promise.reject(4),
  new Promise((resolve, reject) => setTimeout(resolve, 1000)),
])
// Uncaught (in promise) 4
setTimeout(console.log, 0, p50) // Promise   {< rejected >: 4}, rejection occurs first, and the solution after timeout is ignored

let p51 = Promise.race([
  Promise.resolve(1),
  Promise.resolve(),
  Promise.resolve(3),
])
setTimeout(console.log, 0, p51) // Promise   {< fulfilled >: 1}, the iteration order determines the finalization order

let p52 = Promise.race([
  Promise. Reject (3), // the first rejected appointment. The reason for rejection is 3
  New promise ((resolve, reject) = > setTimeout (reject, 1000, 4)), // the second period of rejection. The reason for rejection is 4
])
// Uncaught (in promise) 3
setTimeout(console.log, 0, p52) // Promise   {< rejected >: 3}, the first reason for rejection is the reason for rejection of the contract during the synthesis period
P52. Catch ((reason) = > setTimeout (console. Log, 2000, reason)) // 3. The first reason for rejection is used as the reason for rejection of the composition period, but the browser will not display an unhandled error (uncaught (in promise) 3)

Serial phase synthesis

  • Multiple functions can be combined into one function
function addTwo(x) {
  return x + 2
}
function addThree(x) {
  return x + 3
}
function addFive(x) {
  return x + 5
}

function addTen(x) {
  return addFive(addThree(addTwo(x)))
}
console.log(addTen(7)) // 17
  • Similar to function synthesis, the period can be approximatelyAsynchronously generated valueAnd put itPass to handler, the subsequent period is aboutReturn value of previous periodComing series period about
function addTen(x) {
  return Promise.resolve(x).then(addTwo).then(addThree).then(addFive)
}
setTimeout(console.log, 0, addTen(8)) // Promise {<fulfilled>: 18}
addTen(8).then((result) => console.log(result)) // 18
  • AvailableArray.prototype.reduce()Abbreviation: the above period is about in series
function addTen(x) {
  return [addTwo, addThree, addFive].reduce((pre, cur) => {
    return pre.then(cur)
  }, promise. Resolve (x)) // the merge starting point value (the first parameter of the merge function) is promise. Resolve (x), and the second parameter is addtwo, the first item of the array
}
setTimeout(console.log, 0, addTen(9)) // Promise {<fulfilled>: 19}
addTen(9).then((result) => console.log(result)) // 19
  • It can be finallyencapsulationBecome oneGeneral method
function compose(...fns) {
  return (x) =>
    fns.reduce((pre, cur) => {
      return pre.then(cur)
    }, Promise.resolve(x))
}
addTen = compose(addTwo, addThree, addFive)
addTen(10).then((result) => console.log(result)) // 20

Period expansion

  • There are two features that ECMAScript does not coverCancellation of appointmentandProgress trackingIt has been implemented in many third-party databases

Cancellation of appointment

  • Can provide a temporaryencapsulationTo achieveCancellation periodFunction of
Const startbutton = document.queryselector ('#start') // start button
Const cancelbutton = document.queryselector ('#cancel') // end button
Let cancelbtnhasclickevent = false // whether the end button has added a click event
/* 
  Each time a case in the book clicks the "start" button, it will re instantiate the canceltoken instance, add a click event to the canceltoken, and more and more 'delay cancelled' will be printed
  A global variable cancelbtnhasclickevent is appended here to ensure that only one click event is appended to canceltoken when the "start" button is clicked for the first time
*/

//The canceltoken class wraps an appointment and exposes the solution to the cancelfn parameter
class CancelToken {
  constructor(cancelFn) {
    this.promise = new Promise((resolve, reject) => {
      cancelFn(() => {
        SetTimeout (console. Log, 0, 'delay cancelled') // canceling timing
        Resolve() // scheduled resolution
      })
    })
  }
}

//Click event: start timing and instantiate a new canceltoken instance
function cancellabelDelayedResolve(delay) {
  SetTimeout (console. Log, 0, 'set delay') // start timing
  return new Promise((resolve, reject) => {
    const id = setTimeout(() => {
      SetTimeout (console. Log, 0, 'delay resolve') // triggered after delay
      resolve()
    }, delay)
    //Instantiate a new canceltoken instance
    const cancelToken = new CancelToken((cancelCallback) => {
      cancelBtnHasClickEvent === false &&
        Cancelbutton. Addeventlistener ('click ', cancelcallback) // click the end button to add a click event
      Cancelbtnhasclickevent = true // the end button has added a click event
    })
    Canceltoken. Promise. Then (() = > cleartimeout (ID)) // trigger the scheduled resolution in the token instance
  })
}

Startbutton. Addeventlistener ('click ', () = > cancellabeldelayedresolve (1000)) // click the start button to add a click event

Complete file →

Contract progress notice

  • ES6 does not support monitoring the implementation progress of the contract, which can be realized by extension
//Subclass trackablepromise inherits the parent class promise
class TrackablePromise extends Promise {
  //Subclass constructor, receiving 1 parameter (executor function)
  constructor(executor) {
    const notifyHandlers = []
    //Super() calls the constructor() of the parent class to pass in parameters (executor function)
    super((resolve, reject) => {
      //Execute the executor() function. The parameters are the parameters passed to the trackablepromise subclass, and return the execution result
      return executor(resolve, reject, (status) => {
        console.log(status)
        /* 
          '80% remaining' (after about 1 second)
          '60% remaining' (after about 2 seconds)
          'remaining '(after about 3 seconds)
          'remaining '(after about 4 seconds)
        */
        notifyHandlers.map((handler) => {
          return handler(status)
        })
      })
    })
    this.notifyHandlers = notifyHandlers
  }
  //Add the notify method and receive 1 parameter (notifyhandler function)
  notify(notifyHandler) {
    this.notifyHandlers.push(notifyHandler)
    return this
  }
}

//Create a subclass instance and pass in parameters (executor function)
let p53 = new TrackablePromise((resolve, reject, notify) => {
  function countdown(x) {
    if (x > 0) {
      notify(`${20 * x}% remaining`)
      setTimeout(() => countdown(x - 1), 1000)
    } else {
      resolve()
    }
  }
  countdown(5)
})
console.log(p53) // Promise   {< pending >, notifyhandlers: array (0)}, trackablepromise instance (subclass duration)

P53. Notify ((x) = > setTimeout (console.log, 0, 'progress:', x)) // call the notify() method of the instance and pass in the parameter (notifyhandler function)
P53. Then (() = > setTimeout (console. Log, 0, 'completed') // call the then () method of the instance and pass in the parameter (onresolved handler)
/* 
  'progress: 80% remaining' (about 1 second later)
  'progress: 60% remaining' (about 2 seconds later)
  'progress: 40% remaining' (about 3 seconds later)
  'progress: 20% remaining' (about 4 seconds later)
  'completed' (about 5 seconds later)
*/

p53
  .notify((x) => setTimeout(console.log, 0, 'a:', x))
  . notify ((x) = > setTimeout (console. Log, 0, 'B:', x)) // notice() returns a period of about, and the call is concatenated
p53.then(() => setTimeout(console.log, 0, 'completed'))
/* 
  'A: 80% remaining' (about 1 second later)
  'B: 80% remaining' (about 1 second later)
  'A: 60% remaining' (about 2 seconds later)
  'B: 60% remaining' (about 2 seconds later)
  'A: 40% remaining' (about 3 seconds later)
  'B: 40% remaining' (about 3 seconds later)
  'A: 20% remaining' (about 4 seconds later)
  'B: 20% remaining' (about 4 seconds later)
  'completed' (about 5 seconds later)
*/

Summary & ask questions

  • What is promise type? How to create? What are the different states?
  • What is the role of the actuator function? How to delay its switching state? How to avoid the appointment card in the pending state?
  • How to instantiate a solution? What is its value? What happens if the parameter passed in is also an appointment?
  • How to instantiate a rejected appointment? What are the reasons for their refusal? What happens if the parameter passed in is also an appointment?
  • What are the meanings of promise. Prototype. Then(), promise. Prototype. Catch(), promise. Prototype. Finally()? What parameters are received? According to different parameters, what are the return values?
  • How to understand the “non reentry” of futures contract? Which handlers does it apply to?
  • If more than one handler is added in the same period, in what order will the handler execute when its state changes? How do I pass the resolution value of the appointment and the reason for rejection to the handler?
  • How do I pass resolution values and rejection reasons? How to catch an error object when an error is thrown? Why is it best to use the wrong object uniformly for rejection reasons?
  • Write a piece of code to catch [synchronous and asynchronous] errors in [try / catch and appointment] respectively, and do not affect other (subsequent) code logic
  • Write a piece of code to complete the serialization of multiple asynchronous tasks: ① do not use the period contract to form a “callback hell”; ② use the period contract chain to solve this problem
  • What do promise. All() and promise. Race() mean? What kind of terms does it return under different circumstances?
  • Write a piece of code, concatenate multiple periods, simplify the code with reduce (), and finally encapsulate it into a general method
  • Write a piece of code to realize the following functions: there are two buttons start and end on the page. Click start to instantiate a new appointment and print start. After 1 second, cash it and print success. Click end to cancel the appointment and print end