attention front-end small Ou , read more original technical articles

Asynchronous function

  • ES8 adds a new asynchronous function ( async/await ), which is the application of ES6 contract mode in ECMAScript functions
  • synchronous code execution asynchronous

related code →

Asynchronous function

  • ES8 has expanded the function, adding two keywords async and await

async

  • async keyword is used to declare asynchronous functions, which can be used on the function declarations , function expressions , arrow functions and methods
async function foo() {} // 用在函数声明
let bar = async function () {} // 用在函数表达式
let baz = async () => {} // 用在箭头函数
class Qux {
  async qux() {} // 用在方法
}
  • async keywords let function has asynchronous nature , the code still synchronization evaluated , parameters or closure also has a normal function of the behavior of ordinary JS
async function foo() {
  console.log(1)
}
foo()
console.log(2)
/* 
  1,foo()函数先被求值
  2
*/
  • The value returned by the asynchronous function return Promise.resolve() object by 061541d14f1f5f. Calling the asynchronous function will always return the

    • If the return keyword returns an thenable interface ( callback , contract), the object is then() by the handler
    • If the return keyword returns a regular value, the return value will be treated as resolved period of about (without the return keyword, the return value will be treated as undefined)
async function foo() {
  return 'foo' // 返回原始值
}
console.log(foo()) // Promise {<fulfilled>: "foo"},被当作已解决的期约
foo().then((result) => console.log(result)) // 'foo'

async function bar2() {
  return ['bar'] // 返回没有实现thenable接口的对象
}
console.log(bar2()) // Promise {<fulfilled>: ['bar']},被当作已解决的期约
bar2().then((result) => console.log(result)) // ['bar']

async function baz2() {
  const thenable = {
    then(callback) {
      callback('baz')
    },
  }
  return thenable // 返回实现了thenable接口的非期约对象
}
console.log(baz2()) // Promise {<pending>}
baz2().then((result) => console.log(result)) // 'baz',由then()解包

async function qux() {
  return Promise.resolve('qux') // 返回解决的期约
}
console.log(qux()) // Promise {<pending>}
qux().then((result) => console.log(result)) // 'qux',由then()解包

async function rejectQux() {
  return Promise.reject('qux') // 返回拒绝的期约
}
console.log(rejectQux()) // Promise {<pending>}
rejectQux().then(null, (result) => console.log(result)) // 'qux',由then()解包
// Uncaught (in promise) qux
rejectQux().catch((result) => console.log(result)) // 'qux',由catch()解包
  • throws an error in the asynchronous function will return rejected period is about
async function foo() {
  console.log(1)
  throw 3
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1,foo()函数先被求值
  2
  3
*/
  • asynchronous function rejected the error (not "return the rejected ") 161541d14f214a will not be caught by the asynchronous function
async function foo() {
  Promise.reject(3) // 拒绝的期约(非返回)
}
foo().catch((result) => console.log(result)) // catch()方法捕获不到
// Uncaught (in promise) 3,浏览器消息队列捕获

await

  • Using the await keyword can suspend the asynchronous function code, waiting period to resolve
let p = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 3)
})
p.then((x) => console.log(x)) // 3

// 用async/await重写
async function foo() {
  let p = new Promise((resolve, reject) => {
    setTimeout(resolve, 1000, 3)
  })
  console.log(await p)
}
foo() // 3
  • await will try to the value of the yield ), then pass the value to the expression, and then asynchronously resume execution of the asynchronous function
async function foo() {
  console.log(await Promise.resolve('foo')) // 将期约解包,再将值传给表达式
}
foo()

async function bar2() {
  return await Promise.resolve('bar')
}
bar2().then((res) => console.log(res)) // 'bar'

async function baz2() {
  await new Promise((resolve, reject) => {
    setTimeout(resolve, 1000)
  })
  console.log('baz')
}
baz2() // 'baz'(1000毫秒后)
  • await According to the waiting value, perform different operations

    • If the waiting value is an object thenable callback , date), the object is await
    • If the value of the waiting is the conventional value is treated as period has resolved about (and then from await to unpack)
async function foo() {
  console.log(await 'foo') // 等待原始值,被当作已解决的期约Promise.resolve('foo'),再由await解包
}
foo() // 'foo'

async function bar2() {
  console.log(await ['bar']) // 等待值是没有实现thenable接口的对象,被当作已解决的期约再由await解包
}
bar2() // ["bar"]

async function baz2() {
  const thenable = {
    then(callback) {
      callback('baz')
    },
  }
  console.log(await thenable) // 等待值是实现了thenable接口的非期约对象,由await解包
}
baz2() // 'baz'

async function qux() {
  console.log(await Promise.resolve('qux')) // 等待值是解决的期约
}
qux() // 'qux'
  • Waiting would throw an error synchronous operation, it will return of denial about
async function foo() {
  console.log(1)
  await (() => {
    throw 3 // 抛出错误的同步操作
  })()
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1
  2
  3
*/
  • For of denial about use await , will release error value (about the refusal of return)
async function foo() {
  console.log(1)
  await Promise.reject(3) // 对拒绝的期约使用await,将其返回(后续代码不再执行)
  console.log(4) // 不执行
}
foo().catch((result) => console.log(result)) // 给返回的期约添加拒绝处理程序
console.log(2)
/* 
  1
  2
  3
*/

Limits of await

  • must be in asynchronous function
  • cannot be in top-level contexts (such as <script> tags or modules)
  • can be defined and the asynchronous function can be called immediately
  • The characteristics of asynchronous functions will not expand to nested functions
async function foo() {
  console.log(await Promise.resolve(3)) // 必须在异步函数中使用
}
foo() // 3
;(async function () {
  console.log(await Promise.resolve(3)) // 3,立即调用的异步函数表达式
})()

const syncFn = async () => {
  console.log(await Promise.resolve(3)) // 在箭头函数中使用,箭头函数前一样要加async
}
syncFn() // 3

function foo() {
  // console.log(await Promise.resolve(3)) // 不允许在同步函数中使用
}

async function foo() {
  // function bar() {
  //   console.log(await Promise.resolve(3)) // 错误:异步函数不会扩展到嵌套函数
  // }
  async function bar() {
    console.log(await Promise.resolve(3)) // 需要在bar前加async
  }
}

Stop and resume execution

  • async/await really works is await ( async is just an identifier)

    • JS encountered at runtime await keywords will record suspended where
    • When the value on the right of await , JS pushes the task to the message queue, and the task resumes the execution of the asynchronous function
    • Even if await followed by an immediately available value on the right, the function will pause, and the rest will be asynchronously
// async只是标识符
async function foo() {
  console.log(2)
}
console.log(1)
foo()
console.log(3)
/* 
  1
  2
  3
*/

// 遇到await -> 记录暂停 -> await右边的值可用 -> 恢复执行异步函数
async function foo() {
  console.log(2)
  await null // 暂停,且后续操作变为异步
  // 为立即可用的值null向消息队列中添加一个任务
  console.log(4)
}
console.log(1)
foo()
console.log(3)
/* 
  1
  2
  3
  4
*/
  • If await followed by an appointment, then will have two tasks added to the message queue and asynchronously evaluated

    • first task is the return value of the waiting period, second task is to execute the process after getting the return value
    • tc39 has made one modification to the situation await await Promise.resolve() no longer generates 2 asynchronous tasks, but only 1
async function foo() {
  console.log(2)
  console.log(await Promise.resolve(8))
  console.log(9)
}

async function bar2() {
  console.log(4)
  console.log(await 6)
  console.log(7)
}

console.log(1)
foo()
console.log(3)
bar2()
console.log(5)
/*
  书本顺序:1 2 3 4 5 6 7 8 9
  浏览器顺序:1 2 3 4 5 8 9 6 7(tc39做过1次修改)
*/

Asynchronous function strategy

Implement sleep()

  • You can use asynchronous functions to implement functions similar to JAVA in Thread.sleep() , and add non-blocking pauses to the
function sleep(delay) {
  return new Promise((resolve) => setTimeout(resolve, delay)) // 设定延迟,延迟后返回一个解决的期约
}
async function foo() {
  const t0 = Date.now()
  await sleep(1500) // 暂停约1500毫秒
  console.log(Date.now() - t0)
}
foo() // 1507

Take advantage of parallel execution

  • in sequence waits for 5 random timeouts
async function randomDelay(id) {
  const delay = Math.random() * 1000 // 随机延迟0-1000毫秒
  return new Promise((resolve) =>
    setTimeout(() => {
      console.log(`${id} finished`)
      resolve()
    }, delay)
  )
}

async function foo() {
  const t0 = Date.now()
  await randomDelay(0)
  await randomDelay(1)
  await randomDelay(2)
  await randomDelay(3)
  await randomDelay(4)
  console.log(`${Date.now() - t0} ms elapsed`)
}
foo()
/* 
  0 finished
  1 finished
  2 finished
  3 finished
  4 finished
  3279 ms elapsed
*/

// 用for循环重写
async function foo() {
  const t0 = Date.now()
  for (let i = 0; i < 5; i++) {
    await randomDelay(i)
  }
  console.log(`${Date.now() - t0} ms elapsed`)
}
foo()
/* 
  0 finished
  1 finished
  2 finished
  3 finished
  4 finished
  3314 ms elapsed
*/
  • does not consider the order , you can initialize all the appointments at once and wait for the results separately (to obtain parallel acceleration)
async function foo() {
  const t0 = Date.now()

  // 一次性初始化所有期约
  const p0 = randomDelay(0)
  const p1 = randomDelay(1)
  const p2 = randomDelay(2)
  const p3 = randomDelay(3)
  const p4 = randomDelay(4)

  // 分别等待结果,延迟各不相同
  await p0
  await p1
  await p2
  await p3
  await p4

  console.log(`${Date.now() - t0} ms elapsed`)
}
foo()
/* 
  4 finished
  3 finished
  1 finished
  0 finished
  2 finished
  870 ms elapsed,大幅度降低总耗时
*/

// 用数组和for循环再次包装
async function foo() {
  const t0 = Date.now()
  const promises = Array(5)
    .fill(null)
    .map((item, i) => randomDelay(i))

  for (const p of promises) {
    await p
  }
  console.log(`${Date.now() - t0} ms elapsed`)
}
foo()
/* 
  1 finished
  3 finished
  0 finished
  4 finished
  2 finished
  806 ms elapsed
*/
  • await not executed in order, in order receive the value of each futures contract
async function randomDelay(id) {
  const delay = Math.random() * 1000 // 随机延迟0-1000毫秒
  return new Promise((resolve) =>
    setTimeout(() => {
      console.log(`${id} finished`)
      resolve(id)
    }, delay)
  )
}
async function foo() {
  const t0 = Date.now()
  const promises = Array(5)
    .fill(null)
    .map((item, i) => randomDelay(i))

  for (const p of promises) {
    console.log(`awaited ${await p}`)
  }
  console.log(`${Date.now() - t0} ms elapsed`)
}
foo()
/* 
  1 finished
  4 finished
  0 finished
  awaited 0
  awaited 1
  2 finished
  awaited 2
  3 finished
  awaited 3
  awaited 4
  833 ms elapsed
*/

Serial execution contract

  • Use async/await do phase about chain
function addTwo(x) {
  return x + 2
}
function addThree(x) {
  return x + 3
}
function addFive(x) {
  return x + 5
}
async function addTen(x) {
  for (const fn of [addTwo, addThree, addFive]) {
    x = await fn(x)
  }
  return x
}
addTen(9).then((res) => console.log(res)) // 19
  • Change the function to an asynchronous function, return the date
async function addTwo(x) {
  return x + 2
}
async function addThree(x) {
  return x + 3
}
async function addFive(x) {
  return x + 5
}
addTen(9).then((res) => console.log(res)) // 19

Stack trace and memory management

  • When timeout processing executes and rejection period is about , the error message contains the identifier of the (the function called to create the initial scheduled instance) stack trace information should not see these have returned The function

    • When the JS engine creates an appointment, as much as possible the complete call stack . When an error is thrown, the stack trace information will occupy memory, which will bring some calculation and storage costs.
function fooPromiseExecutor(resolve, reject) {
  setTimeout(reject, 1000, 'bar')
}
function foo() {
  new Promise(fooPromiseExecutor)
}
foo()
/* 
  Uncaught (in promise) bar
  setTimeout (async) // 错误信息包含嵌套函数的标识符
  fooPromiseExecutor // fooPromiseExecutor函数已返回,不应该在栈追踪信息中看到
  foo
*/
  • Replaced with an asynchronous function, will not appear in the error message , and the pointer to the containing function is stored in the nested function (in memory), which will not bring additional consumption
async function foo() {
  await new Promise(fooPromiseExecutor)
}
foo()
/* 
  Uncaught (in promise) bar
  foo
  async function (async)
  foo
*/

Summary & Questions

  • What is the usage of the async keyword? According to the different return values in the function, what are the return values of asynchronous functions?
  • What is the use of the await keyword? According to the different waiting values, what are the circumstances for calling asynchronous functions? What are the restrictions on its use?
  • What happens to the await keyword when JS is running? When will the rest of the function resume execution?
  • Write a piece of code and use asynchronous functions to add non-blocking pauses to the program
  • Write a piece of code, use asynchronous functions to execute multiple appointments in parallel, set the delay of these appointments at random, and calculate the time used after all the appointments are completed
  • Write a piece of code, use asynchronous function to do contract chain

小讴
217 声望16 粉丝