Js 单线程之异步编程

先了解一个概念,为什么 JavaScript 采用单线程模式工作,最初设计这门语言的初衷是为了让它运行在浏览器上面。它的目的是为了实现页面的动态交互,而交互的核心是进行 Dom 操作,这也就决定了必须使用单线程模式,否则就会出现很复杂的线程同步问题。假如有两个同步线程工作,其中一个线程进行了新增 demoA,另一个线程进行了删除 demoA,此时浏览器就无法明确以哪个线程的工作为准,所以 JavaScript 就成了单线程模式工作,单线程工作的优点就是,多个任务,同步执行,简单安全,同时缺点也很明显,如果有一个任务耗时的时间非常非常久,那我们就得排队等待,这就会导致整个页面出现像卡死这种情况。
为了解决这种阻塞问题,JavaScript 将任务的执行模式 分成了两种:
  • 同步模式(Synchronous)
  • 异步模式(Asynchronous)

同步模式

指的是代码中的任务依次执行,后一个任务必须等待前一个任务结束才能开始执行,程序的执行顺序和代码的编写顺序完全一致。举个简单栗子
console.log('start')

function part1 () {
console.log('loading part1')
} function part2 () {
console.log('loading part2')
part1()
} part2() console.log('end') // 顺序结果 start --- loading part2 --- loading part1 --- end
// 同时就会触发概念里面那个问题,如果有一个任务耗时特别长,就会出现页面卡死情况,为了避免这种情况,也就有了另一种模式,异步

异步模式

指的是,不会去等待这个任务的结束才开始下一个任务,对于耗时操作,开启之后,立即执行下一个任务,后续逻辑一般会通过回调函数的方式定义。用代码来举个栗子
console.log('start')

setTimeout (function timer1 () {
console.log('timer1 invoke')
}, 2000) setTimeout (function timer2 () {
console.log('timer2 invoke') setTimeout (function inner () {
console.log('inner')
}, 1000)
}, 1000) console.log('end') // 结果 start --- end --- timer2 invoke --- timer1 invoke --- inner
// 同步任务开始执行,碰到计时器丢到任务队列中,同步任务执行完毕,没有微任务,开始执行宏任务,根据倒计时时间,以及里面是否还有其他对应操作,直到结束。
// js 执行引擎先去做完调用栈里面所有的任务,通过事件循环从消息队列中再取出一个任务出来继续执行,以此类推,同时还能随时往消息队列中放入新的任务,排队等待执行,以上就是基本的概念。

回调函数

所有异步编程方案的根本都是回调函数,回调函数可以理解为一件你想要做的事情,定义他的执行规则,然后交给执行者去执行的函数。举个栗子
function foo (callback) {
setTimeout(function () {
callback()
}, 3000)
} foo(function () {
console.log('这就是一个回调函数')
console.log('调用者定义这个函数,执行者执行这个函数')
console.log('其实就是调用者告诉执行者异步任务结束后应该做什么')
})
// 随之而来,就出现了另一个问题,如果说函数A为回调函数,但是他又接受函数B作为参数,函数B又有一个函数C,这就形成了层层嵌套,就会出现回调地狱。为了解决这个问题,出现了 Promise

Promise

由 CommonJS 社区提出的 Promise,在ES2015 中被标准化,成为语言规范
所为的 Promise 就是一个对象,用来去表示一个异步任务最终结束过后究竟是成功还是失败,初始化由内部对外界作出一个承诺 pending 待定状态,最终成功之后,会变为 Fulfilled 同时会有一个 onFulfilled 回调,如果失败,会变为 Rejected,也会有一个 onRejected 回调,而且一旦由 pending 变为成功或者失败,其状态就不会更改了。
// 基本栗子
const promise = new Promise(function (resolve, reject) {
resolve(200) // 成功 // reject(new Error('rejected')) // 失败
})
// 通过.then 调用
promise.then(function (value) {
console.log('resolved', value)
}, function(error) {
console.log('rejected, error')
})
注释失败代码那一行,结果就是 200成功
注释成功代码那一行,结果就是 失败
里面的.then方法,是返回一个全新的 Promise 对象,它的目的是为了实现一个 Promise 链条,也就是承诺成功或失败之后再返回一个新的承诺,也就是链式调用的方式来解决回调地狱嵌套。总结以下几点:
  • Promise 对象的 then 方法会返回一个全新的 Promise 对象
  • 后面的 then 方法就是在为上一个 then 返回的 Promise 注册回调
  • 前面 then 方法中回调函数的返回值作为后面 then 方法回调的参数
  • 如果回调函数中返回的是 Promise,那后面 then 方法的回调等待它的结束
对于异常处理 onRejected 会自动弹出异常,也还有常用的 .catch 来处理异常

Promise 静态方法

创建一个成功的 Promise.resolve() 对象,反之还有一个 Promise.reject() 创建一个失败的对象

Promise 并行执行

Promise.all([]) 接收一个数组,每一个元素都是一个 Promise 对象,也就是异步任务,当里面所有的异步任务结束后这个方法结束后会返回一个全新的 Promise 对象,这个 Promise 对象 会返回一个数组的结果,里面的每一项都对应着,每一个异步任务的结果,但是只要有一项失败,那就会立即抛出错误。
Promise.race([]) 方法同上,不同的是,只有一项成功,就会返回最新成功的那个结果。

JavaScript 单线程之异步编程的更多相关文章

  1. javascript编程单线程之异步模式Asynchronous

    异步模式Asynchronous 不会等待这个任务结束才开始执行下一个任务,开启之后立即执行下一个任务,后续逻辑一般会通过回调函数的方式定义,异步模式对js 非常重要,没有异步任务单线程的 js 语言 ...

  2. javaScript中的异步编程模式

    1.事件模型 let button = document.getElementById("my-btn"); button.onclick = function(event) { ...

  3. javascript中的异步编程

    正常情况下js都是顺序执行的,但是也有很多场景下实际上是异步操作: 1.定时器都是异步操作 2.事件绑定都是异步操作 3.AJAX中一般我们都采取异步操作(也可以同步) 4.回调函数可以理解为异步(不 ...

  4. JavaScript异步编程原理

    众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...

  5. javascript异步编程的前世今生,从onclick到await/async

    javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...

  6. 5分种让你了解javascript异步编程的前世今生,从onclick到await/async

      javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...

  7. 说一说javascript的异步编程

    众所周知javascript是单线程的,它的设计之初是为浏览器设计的GUI编程语言,GUI编程的特性之一是保证UI线程一定不能阻塞,否则体验不佳,甚至界面卡死. 所谓的单线程就是一次只能完成一个任务, ...

  8. JavaScript 异步编程

    博客地址:https://ainyi.com/96 众所周知,JavaScript 是单线程的,但异步在 js 中很常见,那么简单来介绍一下异步编程 同步编程和异步编程 同步编程,计算机一行一行按顺序 ...

  9. NodeJS的异步编程风格

    NodeJS的异步编程风格 http://www.infoq.com/cn/news/2011/09/nodejs-async-code NodeJS运行环境因其支持Javascript语言和异步编程 ...

随机推荐

  1. String工具类之“前缀比较”StringUtils.startsWith和StringUtils.startsWithIgnoreCase

    (1)字符串以prefix为前缀(区分大小写) StringUtils.startsWith(被比较的字符串,比较字符串) 总结: 根据下面代码发现,上面的例子有部分时错误的,有可能是因为思维原因,他 ...

  2. STM32 标准库

    CMSIS 标准及库层次关系 因为基于Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难.为了解决不同的芯片厂商生产的Co ...

  3. HTML5+CSS3兼容收藏夹

    CSS3选择器兼容IE6~8: Selectivizr 使用方法: <!--[if (gte IE 6)&(lte IE 8)]> <script src="htt ...

  4. iView 一周年了,同时发布了 2.0 正式版,但这只是开始...

    两年前,我开始接触 Vue.js 框架,当时就被它的轻量.组件化和友好的 API 所吸引.之后我将 Vue.js 和 Webpack 技术栈引入我的公司(TalkingData)可视化团队,并经过一年 ...

  5. A小程序与B小程序相互跳转的一点记录

    要点速览: A小程序和B小程序关联同一个公众号 B程序的用户授权 A小程序和B小程序的用户关联 诸葛 io 统计用户访问信息 需求:微信放开小程序互跳的 API 后,一些导流和拉新等活动可以在新的小程 ...

  6. 手绘模型图带你认识Kafka服务端网络模型

    摘要:Kafka中的网络模型就是基于主从Reactor多线程进行设计的. 本文分享自华为云社区<图解Kafka服务端网络模型>,作者:石臻臻的杂货铺 . Kafka中的网络模型就是基于主从 ...

  7. Ubuntu之安装Gradle

    简介 Gradle 是以 Groovy 语言为基础,面向Java应用为主,基于DSL(领域特定语言)语法的自动化构建工具. 现在Android Studio用它来编译APK程序. 前提 Ubuntu官 ...

  8. java基础-字符流

    字符流 * 字符流是可以直接读写字符的IO流 * 字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出.    FileReader * FileRea ...

  9. nodejs教程---基于expressJs框架,实现文件上传(upload)?

    文件上传功能在nodejs初期是一件很难实现的功能,之后出现了formidable勉强能解决这个问题,但是express框架出现之后基于这个框架开发的中间件有更好的方法来处理文件上传,这个中间件就是m ...

  10. Java三大结构

    Java三大结构 顺序结构(基本结构) 选择结构 循环结构 1. 顺序结构 平时一般语句都默认遵循顺序结构 2. 选择结构 2.1 if单选择结构 语法 if(布尔表达式){ //布尔表达式为true ...