更优雅的方式: JavaScript 中顺序执行异步函数
火于异步
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
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/async_function
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/await
为了更易书写和阅读来实现顺序执行异步函数,ES2017 新增了 await 和 async。这次书写体验非常的棒,就像写同步代码一样完成了顺序执行异步的需求。
/**
* 第一个任务
*/
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 实现的顺序执行异步,爬取豆瓣电影截图并按顺序一张张下载图片。
参考
- 《JavaScript编程全解》
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/
转载请注明出处: http://blog.givebest.cn/javascript/2018/04/05/javascript-sync.html
更优雅的方式: JavaScript 中顺序执行异步函数的更多相关文章
- 【JS】JavaScript中的执行环境与作用域
JavaScript中的执行环境定义了变量或函数有权访问的数据(每个函数都有自己的执行环境),全局执行环境是最外围的执行环境,在浏览器中,全局执行环境就是window对象,所以所有的全局变量和函数都是 ...
- [js]javascript中4种异步
javascript中4种异步: 1.ajax 2.定时器 3.事件绑定 4,回调 定时器 //顺序执行 /* var s = 0; for (var i = 0; i < 10000; i++ ...
- 在javascript中关于变量与函数的提升
在javascript中关于变量与函数的提升 一.简介 在javascript中声明变量与函数的执行步骤: 1.先预解析变量或函数声明代码,会把用var声明的变量或者函数声明的代码块进行提升操作 2. ...
- 使用Ajax在javascript中调用后台C#函数
使用Ajax在javascript中调用后台C#函数 最近一段时间在紧跟一个网站的项目,数据库中用户表的UserName要求是唯一的,所以当用户选定一个用户名进行注册时要首先检查该用户名是否已被占用, ...
- JavaScript中的内置函数
JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供 ...
- JavaScript 中对变量和函数声明提前的演示样例
如题所看到的,看以下的演示样例(能够使用Chrome浏览器,然后F12/或者右键,审查元素.调出开发人员工具,进入控制台console输入)(使用技巧: 控制台输入时Shift+Enter能够中途代码 ...
- Springboot中RestTemplate -- 用更优雅的方式发HTTP请求
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率. 我之前的HTTP开发是用ap ...
- 少年,是时候换种更优雅的方式部署你的php代码了
让我们来回忆下上次你是怎么发布你的代码的: 1. 先把线上的代码用ftp备份下来 2. 上传修改了的文件 3. 测试一下功能是否正常 4. 网站500了,赶紧用备份替换回去 5. 替换错了/替换漏了 ...
- Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率. 我之前的HTTP开发是用ap ...
随机推荐
- .net白盒测试
很久没写博客了,刚好这段时间空闲,做点记录 前提:最近部门需要白盒测试的工具,在网上也搜索了很多资料,国内很少有类似的资料(很少公司.net代码进行白盒测试),最后在国外(FQ)网站查找到了部分资料 ...
- awk多分隔符功能及wc命令案列及企业级应用
打印最后一行行号: cat -n /etc/services|tail -1 awk '{print NR $0}' oldboy.txt|tail -1 awk '{print NR $0}' /e ...
- Eclipse常用不常用快捷键
逼格高且常用的7个快捷键:Ctrl+O:列出该类下的所有方法 Ctrl+E:列出打开的所有类 Shift+Enter:在当前行下一行创建空白行(Ctrl+Shift+Enter:在当前行上一行 ...
- 【MyBatis源码分析】Configuration加载(下篇)
元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...
- mvc-dispatchar-servlet.xml文件报错
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- 深入浅出Java分布式系统通信
对java分布式系统通信的理解: 1.集群模式,将相同应用模块部署多份 2.业务拆分模式,将业务拆分成多个模块,并分别部署 3.存储分布式 由于分布式概念太大,我们可以缩小下讨论的范围. 以下分布式的 ...
- 集群session管理问题
转自:http://book.51cto.com/art/201405/439557.htm 先来看一下什么是Session. 用户使用网站的服务,基本上需要浏览器与Web 服务器的多次交互.HTTP ...
- 关于eclipse新建项目问题
新建Dynamic Web Project项目的时候不能有中文名和空格. 不然会报错:The requested resource is not available. 里面的文件名也不能有中文名和空格 ...
- C/S 和B/S 详解 --- 2017-04-25
来源:脚本之家 一.C/S 架构 1. 概念 C/S 架构是一种典型的两层架构,其全程是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两 ...
- kafka概念使用简介注意点
使用场景 大数据量.低并发.高可用.订阅消费场景 概念理解 分区个数与消费者个数 分区个数 = 消费者个数 :最合适状态 分区个数 > 消费者个数 :某些消费者要承担更多的分区数据消费 分区个数 ...