1. 概述

Promise对象是ES6提出的的异步编程的规范。说到异步编程,就不得不说说同步和异步这两个概念。

从字面意思理解同步编程的话,似乎指的是两个任务同步运行,如果这样理解就错了(至少笔者再没有接触到这个概念的时候有这种误解)。同步和异步指的是代码指定执行的顺序(结构化编程范式的执行顺序总是由上至下,由前往后的),如果执行的顺序与代码的相同,就是同步;如果不同,就是异步。

最初,操作系统都是基于命令行的,所有的的语言设计出来也天然是同步的语句,在这种情况下,也不需要异步编程。但是很快,图形操作界面就出来了,所有的程序设计语言都不得不跟GUI打交道了。我们必须了解的是,GUI程序是一个不停绘制的界面程序:

while(done)
{
dosomething();
drawGUI();
}

如果每个循环中执行的任务dosomething()的事件太长,就会导致界面迟迟得不到绘制命令,直观的表现就是卡顿。为了解决这个问题,使用JavaScript作为脚本的浏览器一般都会采用事件循环(Event Loop)的机制:

  1. 将耗时的行为规定为事件,事件与响应回调函数绑定。
  2. 每个循环,优先处理同步代码。
  3. 同步代码完成,按照先后顺序遍历事件。
  4. 在剩下的没有同步代码的循环中,依次执行事件的相应函数。

这样,在单线程的情况下,就修改了任务的执行顺序,实现了异步的机制。因为同步的行为总是很快完成及时进行了界面绘制,界面卡顿的现象也大为改善了。

事件循环机制将UI设备的输入输出规定为事件,实际上,耗时的行为非常多,但是一般都与IO相关,与IO相关的行为,JavaScript都提供了异步行为的代码。例如,这里要用的一个加载图片的实例。

2. 详论

首先准备一个HTML页面PromiseTest.html,在这个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机制的内涵,这样设计并不是为了好玩。

  1. Promise对象代表的是一个预定要做、但是还未开始做的行为。既然是一个行为,当然得进行计划,并对行为结果做出规定:如果成功了,就执行resolve;如果失败了,就执行reject。一般我们可以定义一个function,并且返回一个Promise对象。
  2. 调用返回Promise对象的function,这样这个想要进行的行为就真正启动了。不过resolve和reject只是两个回调函数,那么就通过then方法来规定成功和失败对应的真正的处理函数。

可以看到,这样的设计看起来很繁复,但是却很像是一个同步行为:规定一个未完成行为对象,行为完成了如何处理,行为失败了又如何处理。而这也是Promise的目的:使得异步操作更像是一个同步的行为。

3. 参考

  1. 同步(Synchronous)和异步(Asynchronous)
  2. 简述JS单线程异步实现原理
  3. JavaScript 运行机制详解:再谈Event Loop

JavaScript异步编程1——Promise的初步使用的更多相关文章

  1. javascript异步编程,promise概念

    javascript 异步编程 概述 采用单线程模式工作的原因: 避免多线dom操作同步问题,javascript的执行环境中负责执行代码的线程只有一个 内容概要 同步模式和异步模式 事件循环和消息队 ...

  2. Javascript异步编程之三Promise: 像堆积木一样组织你的异步流程

    这篇有点长,不过干货挺多,既分析promise的原理,也包含一些最佳实践,亮点在最后:) 还记得上一节讲回调函数的时候,第一件事就提到了异步函数不能用return返回值,其原因就是在return语句执 ...

  3. JavaScript异步编程的Promise模式(转)

    异步模式在web编程中变得越来越重要,对于web主流语言Javascript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promis ...

  4. JavaScript异步编程的Promise模式

    参考: http://www.infoq.com/cn/news/2011/09/js-promise http://www.cnblogs.com/rubylouvre/p/3495286.html ...

  5. JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上

    众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...

  6. JavaScript异步编程原理

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

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

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

  8. JavaScript异步编程(2)- 先驱者:jsDeferred

    JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascri ...

  9. Promises与Javascript异步编程

    Promises与Javascript异步编程 转载:http://www.zawaliang.com/2013/08/399.html 在如今都追求用户体验的时代,Ajax应用真的是无所不在.加上这 ...

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

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

随机推荐

  1. 轻巧的批量图片压缩工具imgfast

    现在的手机拍照动辄2M3M,还有7M8m的,如果要把这些文件上传到网上应用,浪费网络,占用资源 所以2022年中秋写了这个小工具,可以批量进行图片文件压缩,支持jpg和png. 文件下载链接https ...

  2. 9.24 多校联测 Day4 总结

    没有罚坐,但好像什么也没做. 反向挂分,RP++. 开考推 T1 的 k=2.推推推,写写写,假了.又假了.还是假的. 此时已过去 1h,开 T2,没有看懂题,又看了一会依旧没有看懂. 开 T3.尝试 ...

  3. mysql查看索引利用率

    -- mysql查看索引利用率 -- 如果很慢把排序去掉,加上limit 并且在where条件中限定表名. -- cardinality越接近0,利用率越低 SELECT t.TABLE_SCHEMA ...

  4. 一、docker的安装及docker-compose安装

    一. 安装docker 1.1安装 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun # https://get.d ...

  5. Navicat Premium破解工具及教程

    使用Navicat_Keygen_Patch5破解Navicat Premium 更新:2019-06-11 10:16 使用Navicat_Keygen_Patch_v5.0_By_DFoX破解Na ...

  6. 在Dash中更灵活地编写回调函数

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/dash-master 大家好我是费老师,使用Dash开发过交互式应用的朋友,想必都不会对回调函数感到 ...

  7. 颠覆了!eShop跟随.Net 8迎来重磅升级,微服务架构与GPT的完美结合!

    .Net 8正式发布了,发布了诸多重大的新功能.新特性! .Net 8新增的功能带来诸多惊喜,还未一一体验完毕呢,我又发现了跟随.Net 8的发布,eShop也迎来重磅升级! eShop一直以来都是微 ...

  8. (Good topic)四因数 (leetcode 181周赛T2)

     四因数难度中等1收藏分享切换为英文关注反馈给你一个整数数组 nums,请你返回该数组中恰有四个因数的这些整数的各因数之和. 如果数组中不存在满足题意的整数,则返回 0 .   示例: 输入:nums ...

  9. Android Recyclerview的item间距实现

    Recyclerview中,提供了一个方法addItemDecoration给我们用于设置item的分割线 下面提供几个常见的分割线效果 注: 下面的SizeUtils是AndroidUtilCode ...

  10. 手把手教Electron+vue,打包vue项目,打包成桌面程序。

    1.现如今前端框架数不胜数,尤其是angular.vue吸引一大批前端开发者,在这个高新技术快速崛起的时代,自然少不了各种框架的结合使用.接下来是介绍electron+vue的结合使用. 2.Elec ...