• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

JavaScript 异步编程

开发技术 开发技术 1周前 (09-15) 20次浏览

博客地址:https://ainyi.com/96

众所周知,JavaScript 是单线程的,但异步在 js 中很常见,那么简单来介绍一下异步编程

同步编程和异步编程

同步编程,计算机一行一行按顺序依次执行代码,当前代码任务执行时会阻塞后续代码的执行;典型的请求-响应模型就是这样,当请求调用一个函数或方法后,需等待其响应返回,然后执行后续代码

异步编程,执行当前任务时(执行中),也可直接执行下一个任务;多个任务并发执行

这就涉及到两个比较容易混淆的概念了:并行并发

并行(parallel):指同一时刻内多任务同时进行;如下图:
JavaScript 异步编程

并发(concurrency):指在同一时间段内,多任务同时进行着,但是同一时刻,只有某一任务执行。使得在宏观上具有多个进程同时执行的效果,但在微观上只是把时间分成若干段,使多个进程快速交替地执行;如下图:
JavaScript 异步编程

异步机制

由上面并发的解释,可以知道单线程可以实现类似多线程机制的这种执行方式;那么 JavaScript 单线程的异步编程可以实现多任务并发执行

重点实现 js 异步的方式,就是事件循环,之前写过关于事件循环的例子,可看:JavaScript 事件循环、异步和同步

事件循环

事件循环涉及到两个概念:消息队列、任务

消息队列:也叫任务队列,存储待处理消息及对应的回调函数或事件处理程序
任务:js 区分同步任务和异步任务,代码执行就是在执行任务,也就是对应同步和异步的代码块

首先 JavaScript 的同步任务是进入主线程的执行栈执行;异步任务则进入消息队列(任务队列),一个存储着待执行任务的队列,严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行

事件循环的流程:检查主线程执行栈是否为空,先执行执行栈中的同步任务,异步任务(回调函数)放入任务队列中,一旦执行栈中的所有的同步任务执行完毕,就会取出任务队列的首部压入执行栈,开始执行,然后继续检查执行栈是否为空,重复这个过程

JavaScript 异步编程

简单来说:事件循环其实就是入栈出栈的循环

这样就能实现异步方式

js 的异步方式

  • setTimeout
  • ajax
  • Promise
  • Generator

setTimeout
即使将时间设置为 0,也会延迟执行,即异步执行。具体可看:setTimeout 时间参数为 0 的探讨

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

ajax

let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() { 
  if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 ) {       
    console.log(xhr.responseText)
  } else {   
    console.log( xhr.status)
  }
}
xhr.open('GET', 'url', false)
xhr.send()

xhr.open 中第三个参数默认为 false 异步执行,改为 true 时为同步执行

Promise
promise 就经常使用了,平常使用 axios 作为请求接口的方式,就是封装了 Promise。当然也可以自己封装使用
具体可看:ES6 Promise 解析及详解三个状态

const promise = new Promise(resolve => {
  setTimeout(() => {
    resolve('hello')
  }, 1000)})
promise.then(value => {
  console.log(value, 'world')
}, error =>{
  console.log(error, 'unhappy')
})

Generator
generator 也叫做生成器,它是 ES6 中引入的一种新的函数类型,内部拥有能够多次启动和暂停代码执行的强大能力,那么也能够用于异步编程中

const axios = require('axios')

const foo = function () {
  return axios({
    method: 'GET',
    url: 'https://cosmos-alien.com/some.url'
  })
}

const main = function *() {
  try {
    let result = yield foo()
    console.log(result)
  } catch (err) {
    console.error(err)
  }
}

let it = main()
let p = it.next().value

p.then((data) => {
  it.next(data)
}, (err) => {
  it.throw(err)
})

博客地址:https://ainyi.com/96


程序员灯塔 , 版权所有
转载请注明原文链接:https://www.wangt.cc/2020/09/javascript-%e5%bc%82%e6%ad%a5%e7%bc%96%e7%a8%8b/
喜欢 (0)