本文详解JavaScript中Promise的初步使用,深入剖析同步与异步的区别及Event Loop机制。通过图像加载实例,对比原生事件回调与Promise写法,展示如何将异步操作转化为类同步风格,提升代码可读性与维护性。
1. 概述
Promise对象是ES6提出的异步编程规范。讨论异步编程,必然涉及同步与异步这两个核心概念。
从字面理解,同步编程似乎指两个任务同时运行,但这是一种误解(至少在接触该概念前笔者也有此误区)。同步与异步指的是代码指定执行的顺序。在结构化编程范式中,执行顺序始终由上至下、由前向后;若实际执行顺序与代码书写顺序一致,即为同步;若不一致,则为异步。
早期操作系统基于命令行,所有语言设计天然为同步语句,因此无需异步编程。随后图形用户界面(GUI)出现,所有程序设计语言不得不与GUI交互。必须明确的是,GUI程序是一个不停绘制界面的程序:
while(done)
{
dosomething();
drawGUI();
}
如果每个循环中执行的任务dosomething()耗时过长,会导致界面迟迟得不到绘制命令,直观表现为卡顿。为解决此问题,使用JavaScript作为脚本的浏览器通常采用事件循环(Event Loop)机制:
- 将耗时行为定义为事件,并将事件与响应回调函数绑定。
- 每个循环优先处理同步代码。
- 同步代码执行完毕后,按先后顺序遍历事件队列。
- 在剩余没有同步代码的循环中,依次执行事件的响应函数。
如此,在单线程环境下修改了任务执行顺序,实现了异步机制。由于同步行为通常快速完成并及时进行界面绘制,界面卡顿现象得以大幅改善。
事件循环机制将UI设备的输入输出规定为事件。实际上,耗时行为众多,但多数与IO相关,JavaScript针对与IO相关的行为提供了异步代码支持。例如,此处将使用一个加载图片的实例。
2. 详论
首先准备一个HTML页面PromiseTest.html,并在该页面中加载JS脚本PromiseTest.js:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="./3rdParty/jquery-3.5.1.js"></script>
<title>样例</title>
</head>
<body>
<div id = "container"> </div>
<script src="./PromiseTest.js"></script>
</body>
</html>
原生JS的图像对象Image,是通过事件形式来实现图像的异步加载:
$(function () {
var img = new Image();
img.onload = function () {
$(img).appendTo($('#container'));
};
img.src = "./img.jpg";
});
为Image的事件句柄onload添加相应函数,当图像装载完成后,将装载好的Image添加到HTML页面某个div元素的子节点下。通过浏览器打开此页面,会直接显示对应地址的图片。
该JS脚本当然也可以通过Promise来改写:
$(function () {
function getImg(uri){
return new Promise(function(resolve, reject){
var img = new Image();
img.onload = function () {
resolve(img);
};
img.onerror = function () {
reject(Error("Load Image Error!"));
}
img.src = uri;
});
}
var imgUri = "./img.jpg";
getImg(imgUri).then(function(img){
$(img).appendTo($('#container'));
}, function(error){
console.error("Failed!", error);
})
});
乍看之下,使用Promise似乎使程序显得更加复杂繁复。但深入理解Promise机制的内涵可知,如此设计并非为了炫技。
- Promise对象代表一个预定要做但尚未开始的行为。既然是一个行为,自然需要计划,并对行为结果做出规定:如果成功,执行resolve;如果失败,执行reject。通常我们可以定义一个function,并返回一个Promise对象。
- 调用返回Promise对象的function,该行为便真正启动。不过resolve和reject只是两个回调函数,因此通过then方法来规定成功和失败对应的真正处理函数。
可见,这种设计看似繁复,却非常像是一个同步行为:规定一个未完成行为对象,明确行为完成时如何处理,行为失败时如何处理。这正是Promise的目的:使得异步操作更像是一个同步的行为。
3. 参考
同步(Synchronous)和异步(Asynchronous)
简述JS单线程异步实现原理
JavaScript 运行机制详解:再谈Event Loop
到此这篇关于JavaScript异步编程之Promise的初步使用的文章就介绍到这了,更多相关js Promise使用内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!