Promise/A+ 规范:诞生与原理初探

在 Philip Roberts 眼中,JavaScript 是一门单线程、异步、非阻塞、解释型脚本语言。我们在享受 JavaScript 异步编程带来的便捷的同时,也在为如何处理异步(或处理异步带来的冗杂的代码)而苦恼。但是,作为一门富有活力的编程语言,JavaScript 也在不断地完善自己的标准与规范,为众多 JavaScript 开发者解决这些苦恼。当我们在谈论如何处理异步时,我们可能会立刻想起回调函数(Callback Functions)。我们可以通过这种神奇的机制完成对每一个异步操作结果的处理。然而,随着我们的代码越来越复杂,异步操作也越来越多,而原始的回调方式暴露出的问题也越来越明显。 好在,Promise 的到来为我们解决了一部分问题。那么究竟是什么使 Promise 具有如此魅力,使得它一度被称为“下一代”异步编程方案呢?我们将在本文中从源码和底层原理层面探讨这些问题。在阅读这篇文章前,我们需要掌握以下内容: JavaScript 事件循环机制 异步编程的基本概念 JavaScript 中回调函数的概念 Promise 规范以及基本使用方式…

面向对象的 JavaScript:封装、继承与多态

在现代编程语言中,我们经常提及面向对象编程(Object-Oriented Programming,OOP)。所谓的面向对象,其实是一种具有对象概念的程序编程典范,同时也是一种程序开发的抽象方针。与函数式编程(Functional Programming,FP)不同,面向对象编程希望把所有的事物都认为是一个对象,而对象可以通过实例化一个类或继承一个对象而获得(函数式编程认为一切皆函数,一个确定的输入对应一个确定的输出,并且不会产生副作用)。 面向对象通常可以采用两种方式实现:prototype 或 class。JavaScript 中对象的实现显然属于前者,而后者的代表性语言有 Java、C++、TypeScript(TypeScript 同时支持这两种方式) 等。 本篇文章将会简单地梳理 JavaScript 中的相关问题。读完本文,您应该能了解到包括但不限于以下内容:类与对象、对象创建的几种模式、对象继承的几种模式、对象方法的重写和重载在 JavaScript 中的实现。 前置知识 如何理解类和对象 类是一类事物的抽象概括,它可能包含数据的类型和对数据的处理方法。对象是某个类的实例化。一个生动的例子也许可以帮助我们加深对它们的理解:生物学家会将地球上的生物划分为界、门、…

异步的 JavaScript:浅析浏览器事件循环

JavaScript 采用严格单线程的工作方式。这意味着 JavaScript 没有创建多个子线程进行异步任务的功能。但事实往往并非如此简单。在使用 JavaScript 开发时,我们也许会发现 JavaScript 的确能够实现异步。这背后的原因,与 JavaScript 采用的事件处理机制有关。这种机制被称为“事件循环”。在详尽阐释事件循环是什么之前,笔者希望您明白为什么 JavaScript 要采用单线程工作。 我们为何需要理解浏览器事件循环 浏览器事件循环是非常底层的知识。尽管我们在工作中并不是必须了解它。但是,要知道 JavaScript 是一种以事件驱动的语言——如果观察仔细的话,您一定能在您的代码中发现事件处理程序的存在,无论您是有意识地还是无意识地。因此,理解浏览器事件循环的工作原理似乎就显得十分必要,因为只有了解浏览器如何处理各种事件和任务,我们才能更好、更完美地使用事件驱动的方式编写更高质量的代码。 JavaScript 为何采用单线程 自互联网被发明以来,随着逐年增加的互联网用户的涌入,单纯的 HTML 和 CSS 已经无法满足用户日益复杂的需求。因此,当年的网景公司(Netscape Communications…

在React Native中使用TypeScript

JavaScript是一门弱类型的编程语言,声明变量时不需要声明变量的数据类型,因此这门语言编写起来具有很强的灵活性。但是换句话说在开发大型项目或多人合作的项目中,JavaScript混乱的变量数据类型常常会让人很头疼。因此,引入“数据类型”的概念就十分有必要了。 关于TypeScript TypeScript是一门由Microsoft开发和维护的JavaScript的超集。TypeScript可以使用JavaScript中的所有代码和编码概念,TypeScript是为了使JavaScript的开发变得更加容易而创建的。 TypeScript 从核心语言方面和类概念的模塑方面对 JavaScript 对象模型进行扩展。 JavaScript 代码可以在无需任何修改的情况下与 TypeScript 一同工作,同时可以使用编译器将 TypeScript 代码转换为 JavaScript。 TypeScript 通过类型注解提供编译时的静态类型检查。 TypeScript 中的数据要求带有明确的类型,JavaScript不要求。 TypeScript 为函数提供了缺省参数值。 TypeScript 引入了 JavaScript 中没有的“类”概念。 TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。 TypeScript的优势 1. 静态输入:静态类型化是一种功能,可以在开发人员编写脚本时检测错误。查找并修复错误是当今开发团队的迫切需求。有了这项功能,…

再谈移动端适配

引言 移动端适配一向是很令人头大的问题,因为随着移动设备型号数量的爆发式增长,手机屏幕尺寸越来越多样化,网页内容自适应屏幕尺寸进行显示的需求也就越来越强烈。原本可能通过百分比/媒体查询等简单手段就可以常见的适配问题,但是对于页面有复杂结构或者视觉上有特殊要求的,就需要通过其他手段来解决了。 像素基础 像素 像素是一个老生常谈的问题了。不论是做前端开发还是做UI设计,都离不开这个话题。其实真要深究起来,像素是一个十分复杂的概念。追溯到上世纪6、70年代,计算机的输出设备还是点阵式打印机,如何使打印机打印出文字和图形?科学家们研究出了很多点组成的阵列,通过控制每一个点的黑白,最终组成文字和图形。现代计算机的显示器也借鉴了这个设计,发明了像素。 像素分为两种: 物理像素 又称设备像素(Device Pixel, DP),这是组成显示设备的最小单位。可以理解为显示器上的一个一个的点,这些点组成一个个阵列。因为这些点间隔太短,排布太密集,所以肉眼观察不到颗粒感,物理像素通过RGB显色系统,分别控制RGB三基色通道的明与暗,形成了各种颜色。这就是所谓的视觉欺骗效果。任何显示设备的物理像素的数量都是不变的,出厂前就已经设定好。 物理像素的单位是pt,计算公式为: 1pt = 1 / 72 inch 设备独立像素…

Await/Async 与 Promise

我经常会遇到这种问题:我想向后端POST几张图片,然后得到后端返回的文件名,这一步调用的函数是A函数。当所有图片都上传成功并且拿到文件名之后,再将文件名传给下一个调用的函数进行下一步处理,这一步调用的函数是B函数。我希望只需要用户触发一次就能按顺序执行这两个函数。然而,事与愿违,Javascript的函数调用似乎是同步的——执行A的同时,B也开始执行!这让我十分苦恼。 异步调用 后来我才了解到,其实Javascript是可以实现异步调用的,但是ES5中只能使用回调的方法实现异步,这将无法避免“回调地狱”的发生。于是,ECMA组织意识到这个问题,并在ES6中提出了Promise的概念。紧接着,ES7又基于Promise提出了async/await的概念。 引用一段对这个概念的评价: async/await是写异步代码的新方式,以前的方法有回调函数和Promise。 async/await是基于Promise实现的,它不能用于普通的回调函数。 async/await与Promise一样,是非阻塞的。 async/await使得异步代码看起来像同步代码,这正是它的魔力所在。 一个简单的例子 有一段这样的代码: async function test () { return 'hello world' } let result…

JS中on函数的回调方法

这个坑是我在开发寒假比赛项目的时候踩到的。大致的需求就是实现一个图片旋转方法,当图片的旋转角为逆时针90度时将图片传递给这个函数,在函数内部生成Canvas进行顺时针旋转90度的处理,最后将处理之后的结果返回出来。复现问题为了便于复现这个坑,我并没有重新写一个Demo,而是直接将代码展示出来。当时我的代码如下:utils.jsconst utils = { rotateImg: (imgSrc, vue) => { function getObjectURL (object) { return (window.URL) ? window.URL.createObjectURL(object) : window.webkitURL.createObjectURL(object) } function dataURLtoBlob (dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.…

寒假比赛总结(八) - 比赛总结

前言到今天(2018-03-01)20点,为期一个多月的寒假比赛就结束了。按照惯例,每次比赛结束都写一些总结,把比赛过程中学到了什么、有哪些地方做得好的、哪些地方没做好的都记录一下。也可以当作反思。在比赛中吸取经验,这样会成长得更快。学到了什么规范的操作无论做什么事情,规范是必需遵守的。在比赛时,为了更好地与后端进行合作,我从前端页面的角度制定了一篇文档,在上面详细描述了每个页面所需接口的字段名、方法等等。(这篇文档目前还在:http://docs.lenconda.top/petlog/)在实际的操作中,我前端这边是严格按照文档规定的格式编写调用后端接口的逻辑。然而,后端似乎并没有认真按照这篇文档的规范进行编写:很多接口都是规定GET方法,后端却只允许POST方法;有很多接口的字段存在拼写错误(avatar拼成avater、字段名中少了s或多了s、follow漏了ed(原本是followed)等等),给前后端对接交互造成很大的麻烦,也浪费了很多时间(我们从2月26日开始对接,到2月28日修改完Bug进入预备阶段,前后花了两天的时间),而且后端接口初次测试十有八九都是500,这些500中肯定有很多是没有遵守规范造成的。这件事给我很深的感触,我认为前后端分离的开发模式下,规范一定是要严格遵守的东西。但是就我这次和两位后端的合作过程来看,家园的研发培训时并没有强调规范的重要性,或者说家园研发的新生并没有很强的规范意识,…