火于异步

1995年,当时最流行的浏览器——网景中开始运行 JavaScript (最初称为 LiveScript)。 1996年,微软发布了 JScript 兼容 JavaScript。随着网景、微软竞争而不断的技术更新,在 2000年前后,JavaScript 相关的技术基础准备就绪。 随后到 2005 年前后,以 Google 为首开始重视使用 AJAX(即 Asynchronous JavaScript and XML),使得复杂的网页交互体验接近桌面应用。

然后,随着 Web 应用变得越来越复杂 ,JavaScript 的生态和重要性也日益提升,YUI、prototype.js、jQuery 等各种库相应登场,随之而来就到了 JavaScript 的繁荣期。

2008年,Google 发布了 JavaScript 引擎 V8 大大改善了 JavaScript 的执行速度,进一步推动了 JavaScript 的繁荣,也为 JavaScript 进军服务器端打下了基础(如:Node.js)。

顺序执行异步函数

异步为 JavaScript 带来非阻塞等优势的同时,同时也在一些场景下带了不便,如:顺序执行异步函数,下面总结了一些常用的方法。

1. "回调地狱"

随着应用复杂度几何式增加,我们可能遇到下面“回调地狱”式的代码。

// 第一个任务
function task1 (callback) {
setTimeout(() => {
console.log('1', '我是第一个任务,必须第一个执行');
callback && callback(1);
}, 3000);
} // 第二个任务
function task2 (callback) {
setTimeout(() => {
console.log('2', '我是第二个任务');
callback && callback(2);
}, 1000);
} // 第三个任务
function task3 (callback) {
setTimeout(() => {
console.log('3', '我是第三个任务');
callback && callback(3);
}, 1000);
} // 所有任务
function allTasks () {
task1((cb1) => {
if (cb1) {
task2((cb2) => {
if (cb2) {
task3((cb3) => {
if (cb3) {
// 顺序完成所有任务
}
})
}
});
}
});
} allTasks(); /**
* 3秒后
* 1 我是第一个任务,必须第一个执行
* 1秒后
* 2 第二个任务
* 1秒后
* 3 第三个任务
*/

2. Promise

为了避免“回调地狱”带来的复杂性和不易阅读,ES6 推出了 Promise。这次实现起来简单多了,但还存在 Promise 中嵌套多层 Promise 的问题,似乎又回到了类似“回调地狱”的问题上。

new Promise(resolve => {
setTimeout(() => {
console.log('1', '我是第一个任务,必须第一个执行');
resolve(1);
}, 3000);
}).then((val) => { new Promise(resolve => {
setTimeout(() => {
console.log('2', '我是第二个任务');
resolve(2);
}, 1000);
}).then(val => {
setTimeout(() => {
console.log('3', '我是第三个任务');
}, 1000);
}); });
/**
* 3秒后
* 1 我是第一个任务,必须第一个执行
* 1秒后
* 2 第二个任务
* 1秒后
* 3 第三个任务
*/

3. Await、Async

确保支持,详细见:https://caniuse.com/#search=async

为了更易书写和阅读来实现顺序执行异步函数,ES2017 新增了 awaitasync。这次书写体验非常的棒,就像写同步代码一样完成了顺序执行异步的需求。

/**
* 第一个任务
*/
function task1 () {
return new Promise(resolve => {
setTimeout(() => {
console.log('1', '我是第一个任务,必须第一个执行');
resolve('done');
}, 3000);
});
} /**
* 第二个任务
*/
function task2 () { return new Promise(resolve => {
setTimeout(() => {
console.log('2', '第二个任务');
resolve('done');
}, 1000)
});
} /**
* 第三个任务
*/
function task3 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('3', '第三个任务');
reject('error');
}, 1000);
});
} /**
* 第四个任务
*/
function task4 () {
return new Promise(resolve => {
setTimeout(() => {
console.log('4', '第四个任务');
resolve('done');
}, 2000);
})
} /**
* 所有任务
*/
async function allTasks () {
await task1();
await task2();
await task3();
await task4();
} // 执行任务
allTasks(); /**
* 3秒后
* 1 我是第一个任务,必须第一个执行
* 1秒后
* 2 第二个任务
* 1秒后
* 3 第三个任务
* Uncaught (in promise) error
*/
完整案例

基于 Node.js,通过 Await 、Async、Promise 实现的顺序执行异步,爬取豆瓣电影截图并按顺序一张张下载图片。

参考

转载请注明出处: http://blog.givebest.cn/javascript/2018/04/05/javascript-sync.html

更优雅的方式: JavaScript 中顺序执行异步函数的更多相关文章

  1. 【JS】JavaScript中的执行环境与作用域

    JavaScript中的执行环境定义了变量或函数有权访问的数据(每个函数都有自己的执行环境),全局执行环境是最外围的执行环境,在浏览器中,全局执行环境就是window对象,所以所有的全局变量和函数都是 ...

  2. [js]javascript中4种异步

    javascript中4种异步: 1.ajax 2.定时器 3.事件绑定 4,回调 定时器 //顺序执行 /* var s = 0; for (var i = 0; i < 10000; i++ ...

  3. 在javascript中关于变量与函数的提升

    在javascript中关于变量与函数的提升 一.简介 在javascript中声明变量与函数的执行步骤: 1.先预解析变量或函数声明代码,会把用var声明的变量或者函数声明的代码块进行提升操作 2. ...

  4. 使用Ajax在javascript中调用后台C#函数

    使用Ajax在javascript中调用后台C#函数 最近一段时间在紧跟一个网站的项目,数据库中用户表的UserName要求是唯一的,所以当用户选定一个用户名进行注册时要首先检查该用户名是否已被占用, ...

  5. JavaScript中的内置函数

    JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供 ...

  6. JavaScript 中对变量和函数声明提前的演示样例

    如题所看到的,看以下的演示样例(能够使用Chrome浏览器,然后F12/或者右键,审查元素.调出开发人员工具,进入控制台console输入)(使用技巧: 控制台输入时Shift+Enter能够中途代码 ...

  7. Springboot中RestTemplate -- 用更优雅的方式发HTTP请求

    RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率. 我之前的HTTP开发是用ap ...

  8. 少年,是时候换种更优雅的方式部署你的php代码了

    让我们来回忆下上次你是怎么发布你的代码的: 1. 先把线上的代码用ftp备份下来 2. 上传修改了的文件 3. 测试一下功能是否正常 4. 网站500了,赶紧用备份替换回去 5. 替换错了/替换漏了 ...

  9. Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)

    RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率. 我之前的HTTP开发是用ap ...

随机推荐

  1. Luogu3242:[HNOI2015]接水果

    题面 Luogu3242 Sol 考虑每个盘子怎样才能接到一个水果 分两种情况: 盘子的\(x, y\)在一条链上,那么水果的两点就要在这条链之外 不在的话,水果的两点就分别在盘子的两点的子树中 记录 ...

  2. .NET Core使用skiasharp文字头像生成方案(基于docker发布)

    一.问题背景 目前.NET Core下面针对于图像处理的库微软并没有集成,在.NET FrameWork下我们已经习惯使用System.Drawing类库做简单的图像处理,到了.NET Core下一脸 ...

  3. Docker 基础技术之 Linux namespace 详解

    Docker 是"新瓶装旧酒"的产物,依赖于 Linux 内核技术 chroot .namespace 和 cgroup.本篇先来看 namespace 技术. Docker 和虚 ...

  4. ### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to chec

    数据库连接超时,是数据库连接时的相关配置写错,例如:数据库密码,驱动等问题

  5. 在Simplicity Studio下创建适用于EFR32的工程项目

    1.使用平台 使用平台描述了在Simplicity Stdio下创建工程时所使用的操作系统与软件版本等. 操作系统:Windows 10 Simplcity Studio版本:Simlicity St ...

  6. Asp.Net MVC 文件管理Demo(文件展示,上传,下载,压缩,文件重命名等)

    之前 ,有想做一个文件管理页面. 参考了 许多资料,终于完成了一个基于Asp.net MVC 的文件管理Demo.界面如下.   一,实现功能及相关技术 文件管理Demo基于Asp.NET MVC , ...

  7. 基于I2C总线的MPU6050学习笔记

    MPU6050学习笔记 1. 简述 一直想自己做个四轴飞行器,却无从下手,终于狠下决心,拿出尘封已久的MPU6050模块,开始摸索着数据手册分析,一步一步地实现了MPU6050模块的功能,从MPU60 ...

  8. PHP开发程序员的学习路线

    PHP开发程序员的学习路线 兄弟连PHP培训,简单为大家梳理了每个阶段PHP程序员的技术要求,来帮助很多PHP程序做对照设定学习成长目标. 第一阶段:基础阶段(基础PHP程序员) 重点:把LNMP搞熟 ...

  9. 笔记:Spring Cloud Zuul 快速入门

    Spring Cloud Zuul 实现了路由规则与实例的维护问题,通过 Spring Cloud Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获取了 ...

  10. 桶排序/基数排序(Radix Sort)

    说基数排序之前,我们先说桶排序: 基本思想:是将阵列分到有限数量的桶子里.每个桶子再个别排序(有可能再使用别的排序算法或是以递回方式继续使用桶排序进行排序).桶排序是鸽巢排序的一种归纳结果.当要被排序 ...