[Effective JavaScript 笔记]第7章:并发--个人总结

前言

这一章的内容学到了事件队列和异步的API。js只是运行在其他应用程序的脚本语言。js即依赖于应用程序,也独立与应用程序。可以使它可以在多平台,多种环境上运行。ECMAScript标准中没有关于并发的说明。这章讨论的是一些常用的方法,使用事件和异步API是js编程的基础部分。异步API,有setTimeout,setInterval。

第61条:不要阻塞I/O事件队列

个人总结

js是构建在事件之上的单线程语言。js处理交互都以事件的方法进行传递的,监听事件的处理函数,都根据事件队列的执行相应的监听函数。

同步处理

同步处理,在一个I/O请求中,会等待输入的内容。如果没有输入会一直等待下去,直到输入有结果。这个时候,在多线程的语言里可以开另一个线程处理其他计算,但js是单线程的语言,只能一直等,也就是阻塞了,浪费了计算机资源。

异步处理

在js中,可以为一个I/O操作提供一个回调函数,然后程序会继续处理下面的代码。直到I/O有输入时,回调函数才会执行相关操作。这是由事件队列的特性来实现的,这样就可以实现无阻塞的代码。

提示

  • 异步API使用回调函数来延缓处理代价高昂的操作以避免阻塞主应用程序

  • js并发地接收事件,但会使用一个事件队列按序地处理事件处理程序
  • 在应用程序事件队列中绝不要使用阻塞的I/O

第62条:在异步序列中使用嵌套或命名的回调函数

个人总结

理解操作序列的最简单的方式是异步API的发起操作而不是执行操作。所以在发起操作后的代码会先执行,而到后面的事件循环的轮次中,被注册的事件处理程序才会执行。串联已完成的异步操作,可以使用嵌套的方式来进行。但层次过多会导致代码很乱,很长。减少嵌套的方法:使用命名函数,使用bind方法来绑定。把这些方式结合在一起使用,可以更好解决问题。

提示

  • 使用嵌套或命名的回调函数按顺序地执行多个异步操作

  • 尝试在过多的嵌套的回调函数和尴尬的命名的非嵌套回调函数之间取得平衡
  • 避免将可被并行执行的操作顺序化

第63条:当心丢弃错误

个人总结

管理异步编程,调试不太容易,错误发生的地方和错误捕获的地方不好定位。这里对异步操作把错误的信息的以回调函数参数的形式向外层传递。在回调函数中对错误进行处理,可以使代码可以正常运行。

提示

  • 通过编写共享的错误处理函数来避免复制和粘贴错误处理代码

  • 确保明确地处理所有的错误条件以避免丢弃错误

第64条:对异步循环使用递归

个人总结

异步循环,62条所说的一样,这里的循环只是同时发起了多个操作,但并不是执行操作。所以无法在执行操作中对循环进行中止。把循环的操作改写成函数的递归,把异步的发起和执行进行序列化。但又会有一个新的问题,js环境通常在内存中保存一块固定的区域,称为调用栈,用于记录函数调用返回前下一步该做什么。这是以栈的方式来存储的“先进后出”。但如果这样的调用次数过多,会导致栈空间被耗尽,最终会抛出异常,即栈溢出。

提示

  • 循环不能是异步的

  • 使用递归函数在事件循环的单独轮次中执行迭代
  • 在事件循环的单独轮次中执行递归,并不会导致调用栈溢出

第65条:不要在计算时阻塞事件队列

个人总结

第61条解释了异步API如何防止一段程序阻塞应用程序的事件队列。如果是一段正常的执行代码一直占用线程,事件队列中的操作无法执行。这段时间里在浏览器环境中,无法响应
用户操作。Web客户端平台的Worker API,可以处理纯数据的计算,从而防止计算时对事件队列的阻塞。

提示

  • 避免在主事件队列中执行代价高昂的算法

  • 在支持Worker API的平台,该API可以用来在一个独立的事件队列中运行长计算程序
  • 在Worker API不可用或代价昂贵的环境中,考虑将计算程序分解到事件循环的多个轮次中

第66条:使用计数器来执行并行操作

个人总结

当处理多个并发时,无法保重回调函数中参数的顺序。导致后期代码无法正确运行,对于每次发起操作记一次数,返回时对对应的返回结果进行记录。回调函数再对记录的结果进行处理。可以保证程序按预定步骤进行运行。

提示

  • js应用程序中的事件发生是不确定的,即顺序是不可预测的

  • 使用计数器避免并行操作中的数据竞争

第67条:绝不要同步地调用异步的回调函数

个人总结

异步的返回结果,可以保存在一个缓存中。在这种情况下,再进行多文件同步下载,可以使用缓存中的数据,所以回调函数可以同步地执行。但就像64条上的调用栈有可能会出现问题,会导致栈空间耗尽。回调函数也使用异步调用,使用setTimeout来调用对应的回调函数。

提示

  • 即使可以立即得到数据,也绝不要同步地调用异步回调函数

  • 同步地调用异步的回调函数扰乱了预期的操作序列,并可能导致意想不到的交错代码
  • 同步地调用异步的回调函数可能导致栈溢出或错误地处理异常
  • 使用异步的API,比如setTimeout函数来调度异步回调函数,使其运行于另一回合

第68条:使用promise模式清洁异步逻辑

个人总结

使用promise模式,可以把多层嵌套函数,改写成一种同步传入回调函数的方式。这样可以利用各种工具函数对其进行处理。如then,when,join,select等。

提示

  • promise代表最终值,即并行操作完成时最终产生的结果

  • 使用promise组合不同的并行操作
  • 使用promise模式的API避免数据竞争
  • 在要求有意的竞争条件时使用select(也被称为choose)

总结

  • 异步调用,利用事件队列防止阻塞

  • 函数的多次递归调用,调用栈可能会耗尽
  • 纯计算,使用web客户端的Worker API
  • 使用计数器,可以保证异步的结果顺序
  • 使用处理异步调用的工具框架
  • 可以防止数据竞争
时间: 2024-11-10 11:40:09

[Effective JavaScript 笔记]第7章:并发--个人总结的相关文章

[Effective JavaScript 笔记]第5章:数组和字典--个人总结

前言 这节里其实一直都在讨论对象这个在js中的万能的数据结构.对象可以表式为多种的形式,表示为字典和数组之间的区别.更多的我觉得这章讨论多的是一些对应实现功能的相关操作,有可能出现的bug以及如何避免来修复这些bug.比如下面会说到的for...in枚举属性的操作,可能因为对原型的一些操作,最终造成数据对象的操作的破坏.对于属性顺序有要求的如何处理,对类数组如何处理等.下面再一起一条一条回顾一下,这章里的主要内容.我觉得没必要讲的会一语带过,相比前面的几章,个人觉得这章的内容重点很少,注意几点就

[Effective JavaScript 笔记]第6章:库和API设计--个人总结

前言 又到了一章的总结,这章里的内容.是把我从一个代码的使用者,如何换位成一个代码的编写者.如何让别人用自己的代码更容易,不用去注意太多的无用细节,不用记住冗长的函数名.在使用API时怎样避免使用者会出现理解的偏差.如何处理一些特殊敏感的值,参数如何设置可以更好地自说明,如何减少API对状态的依赖,如何使API更加灵活,更利于用户的编写.下面一一展开介绍,对应的也会说明每条对应希望给到的是哪方面的建议! 第53条:保持一致的约定 个人总结 不要去创造一个独特的API,要使用一些大家惯用的词汇,参

[Effective JavaScript 笔记]第2章:变量作用域--个人总结

前言 第二章主要讲解各种变量作用域,通过这章的学习,接触到了很多之前没有接触过的东西,比如不经常用到的eval,命名函数表达式,with语句块等,下面是一个列表,我对各节的一点点个人总结,很多都是自己的收获和认识.可能有很多认识的误区,毕竟水平有限.如果有那里认识不对的地方,还希望可以在评论中指出来,这样可以得到大家在学习的帮助,也是很不错的. 第8条:尽量少用全局对象 个人总结: 解释全局对象在JS中定义的随意性,导致所有人都可以去定义去修改,导致命名冲突.对这样的全局对象进行依赖,导致不可知

[Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+1}" 反射获取函数源代码的功能很强大,使用函数对象的toString方法有严重的局限性.toString方法的局限性ECMAScript标准对函数对象的toString方法的返回结果(即该字符串)并没有任何要求.这意味着不同的js引擎将产生不同的字符串,甚至产生的字符串与该函数并不相关. 如果函数

[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能.程序员面临一个选择:应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数.字符串表示代码不够灵活的一个重要原因是:它们不是闭包. 闭包回顾 看下面这个图 js的函数值包含了比调用它们时执行所需要的代码还要多的信息.而且js函数值还在内部存储它们可能会引用

[Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //"number" typeof "s";//"string" typeof null;//"object":ECMAScript把null描述为独特的类型,但返回值却是对象类型,有点困惑. 可以使用Object.prototype.t

[Effective JavaScript 笔记]全书总结

这本书中就像它前言中说的那样,这本书不是给初学者的.需要一定的基础,而且有一定的编码实践,才能很好的理解书里讲到的内容.学习一门编程语言,需要熟悉它的语法.形式和结构,这样才会编写合法的.符合语义的.具有意义和行为正确的程序.此书的目的是加深理解如何有效地使用js构建更可预测的.可靠和可维护的js应用程序和库.所有章节都是围绕着这几块来展开的. 目录 第1章 让自己习惯JavaScript 第1条:了解你使用的js版本 第2条:理解JavaScript的浮点数 第3条:当心隐式的强制转换 第4条

[读书笔记]《Effective Java》第10章并发

第66条:同步访问共享的可变数据 同步的意义. 正确地使用同步可以保证没有任何方法会看到对象处于不一致的状态中. 进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护的之前所有的修改效果. Java语言规范保证读或者写一个变量是原子的,除非这个变量的类型为long或者double. 对于原子数据的读取,Java语言规范并不保证一个线程写入的值对于另一个线程将是可见的. 对于共享的数据,即使数据是原子可读写的,也要使用同步. 活动性失败:因为JVM的优化,部分代码无法执行. 1 /** 2

[Effective JavaScript 笔记] 第一章:让自己习惯javascript小结

在这里整理一下,每条对应的提示 第1条:了解使用的js版本 确定应用程序支持的js的版本(浏览器也是应用程序噢) 确保使用的js特性是应用程序支持的(要不写了也运行不了) 总是在严格模式下编写和测试代码(面向未来编程) 合并代码时注意不同声明的严格模式(还是用第二种解决方案吧,省心) 第2条:理解JavaScript的浮点数 js的数字都是双精度的浮点数 js的整数仅仅是双精度浮点数的一个子集,不是单独的一个类型 位运算将数字视为32位的有符号整数 当心浮点运算的精度问题 第3条:当心隐式的强制