撩课-Web架构师养成系列(第二篇)-async
前言
Web架构师养成系列共15篇,每周更新一篇,主要分享、探讨目前大前端领域(前端、后端、移动端)企业中正在用的各种成熟的、新的技术。部分文章也会分析一些框架的底层实现,让我们做到知其然知其所以然。
本篇为第二篇,上一篇:撩课-Web架构师养成系列第一篇
本篇文章阅读需要时长:约15分钟
一、先了解异步?
关于"异步",我们可以这么理解: 一个任务拆分成两段,先执行第一段,然后转而执行其他任务,等到某个时间点,再回过头执行第二段。
比如,你要做土豆炖牛肉,当开始煮牛肉的时候发现土豆没了,可以先让牛肉煮着,然后去买土豆、洗好、切好,再把土豆放到锅里一起煮。
这种不连续的执行,就叫做异步。相应地,如果是连续的执行,那么就叫做同步。
1.1 JS中常见的异步编程方式?
异步编程的目标就是让代码的执行更加类似于同步编程,开发中比较常用的方式主要包括: ) 回调函数实现
) 发布订阅、通知
) 事件监听
)Promise/A+ 和 生成器函数
)async/await
在ES6之前,我们更多地是使用回调函数来实现异步编程。
1.2 认识回调函数
回调函数就是把任务拆解成两部分,把任务的第二部份单独写在一个函数里面,等到执行完其它任务重新执行这个任务的时候,就直接调用这个函数,从而达到异步效果。 案例如下: /**
* 土豆炖牛肉
* @param step1 牛肉
* @param callback 回调
*/
let cook = (step1, callback) => {
// 1. 煮牛肉
console.log(`烧水煮${step1}`);
// 2. 放入土豆(5秒后执行)
setTimeout(() => {
let step2 = '放入土豆';
callback(step2);
}, )
}; // 1. 先煮牛肉
cook('牛肉', (data) => {
console.log(data);
}); // 2. 做其它事, 5s后放入土豆
console.log('买土豆');
console.log('洗土豆');
console.log('切土豆');
运行结果
虽然回调函数能够实现异步,但是回调函数存在以下问题: ) 回调地狱问题
异步多级依赖的情况下会层层嵌套,代码难以阅读的维护; )可能会造成多个异步在某一时刻获取所有异步的结果; ) 异步不支持try/catch
回调函数是在下一事件环中取出,
所以一般在回调函数的第一个参数都是用来预置错误对象 )不能通过return返回结果
二、异步改进方案-Promise
2.1 什么是Promise?
promise,承诺。在代码中我们可以这么理解:此处我先许下个承诺,过了一定时间后我带给你一个结果。
那么,在这一段时间中做什么?
我们可以进行异步操作,比如请求网络数据、耗时运算、读写本地文件等
2.2 Promise的三种状态?
) Pending
Promise对象实例创建时候的初始状态
) Fulfilled
成功的状态
) Rejected
失败的状态
比如:你发邮件给老板说要加工资,这时候你就要"等待"他的邮件回复,他可以立马给你回复,如果同意了,表示"成功";如果不同意,表示"失败",当然他也可以一直不同意;但是这期间不影响你做其它事情。 在实际开发中,我们可以通过then 方法,来指定Promise 对象的状态改变时确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)。 来,一起认识下promise的几种操作方式和常用方法: 构建Promise
// promise的方法会立刻执行;
// 两个输出都会打印
let promise = new Promise(() => {
console.log('喜欢IT');
});
console.log('就上撩课');
promise也可以代表未来的一个值
一个promise实例可以多次调用then,当成功后会将结果依次执行。 let promise = new Promise((resolve, reject) => {
ajax.get(BASEURL + 'api/goods/', (err, data)=>{
if (err) return reject(err);
resolve(data);
})
});
promise.then(data => {
console.log(data);
});
promise.then(data => {
console.log(data);
});
promise也可以代表一个不用返回的值
// 代表一个用于不会返回的值
let promise = new Promise((resolve, reject) => { });
promise.then(data => {
console.log(data);
});
Promise.resolve
返回一个Promise实例,这个实例处于resolve状态。 Promise.resolve('成功获取结果').then(data=>{
console.log(data);
});
Promise.reject
返回一个Promise实例,这个实例处于reject状态。 Promise.reject('获取结果失败').then(data=>{
console.log(data);
},err=>{
console.log(err);
})
Promise.race
该方法用于接收一个数组,数组内都是Promise实例,返回一个Promise实例,这个Promise实例的状态转移取决于参数的Promise实例的状态变化。 当参数中任何一个实例处于resolve状态时,返回的Promise实例会变为resolve状态。如果参数中任意一个实例处于reject状态,返回的Promise实例变为reject状态。 Promise.race(
[readFiles('./a.txt'),
readFiles('./b.txt')]).then(data=>{
console.log({data})
},(err)=>{
console.log(err)
});
2.3 案例实操
我们再用promise实现上面发邮件加工资的案例:
情况一 :
在一定时间后(假设5s后),老板回复了邮件,可以是以下两种情况: let addWages = ()=>{
return new Promise((resolve, reject) => {
setTimeout(function () {
// 公司账户余额
let currentMoney = ;
// 公司账户余额 > 100w
if (currentMoney > ) {
resolve('同意加薪');
} else {
resolve('不同意加薪');
}
}, )
})
};
addWages().then(data => {
console.log(data);
}, data => {
console.log(data);
}); // 运行结果:同意加薪
情况二 :
公司账户已经没钱,没法加工资了,表现形式如下: let addWages = ()=>{
return new Promise((resolve, reject) => {
throw new Error('你表现不够优秀!');
})
};
addWages().then(data => {
console.log(data);
}, data => {
console.log('这里输出:' + data);
});
我们可以采用then的第二个参数捕获reject返回结果或者捕获失败,当然也可以通过.catch函数进行捕获。
三、promise可以解决回调函数带来的问题
前面的案例描述已经验证了promise支持catch,此外,通过promise也能够返回结果给外部。我们再一起看看promise如何解决回调地狱和同步异步结果。
3.1 解决回调地狱
案例场景:在文档a.txt中存放正文档b.txt的路径,在文档b.txt中存放正文档c.txt的路径, 我们要取出文档c.txt里面的内容。 构造函数实现: /* a.txt -> b.txt -> c.txt -> 输出内容*/
let fs = require('fs');
let readFiles = ()=>{
// 回调1
fs.readFile('./a.txt','utf8', (err,data)=>{
if(err) return console.log(err);
// 回调2
fs.readFile(data,'utf8',function(err,data){
if(err) return console.log(err);
// 回调3
fs.readFile(data,'utf8',function(err,data){
if(err) return console.log(err);
console.log(data);
})
})
})
}; /*
调用输出结果:
喜欢IT, 就上撩课(itlike.com)
*/
readFiles();
通过promise解决回调地狱: let fs = require('fs'); // 1. 初始化promise
let readFiles =(filePath)=>{
return new Promise((resolve,reject)=>{
fs.readFile(filePath,'utf8',(err,data)=>{
if(err) return reject(err);
resolve(data);
})
})
}; // 2. 类似于链式的调用方式
readFiles('./a.txt').then((data)=>{
return readFile(data);
}).then((data)=>{
// 获取b.txt中内容
return readFile(data);
}).then((data)=>{
// 输出c.txt中内容
console.log(data)
}).catch((err)=>{
console.log(err)
});
3.2 在同一时刻同步所有异步产生的结果
该场景在实际开发中有很多应用场景,比如:我们要提交一个操作时,需要结合之前的两个异步请求的结果才能进行。 再比如:你要进行下一个运算时,需要前面两个异步运算的结果才能进行。我们还是通过读取文件的案例来进行举例。 常规方式实现: let fs = require('fs');
// 1. 统一输出所有异步产生的结果
let allContent = {};
let logAllContent = (key,data)=>{
allContent[key] = data;
if(Object.keys(allContent).length === ){
console.log(allContent)
}
}; // 2. 分别异步读取文件中的内容
fs.readFile('./a.txt', 'utf8', function (err, data) {
if (err) return console.log(err);
logAllContent(data);
});
fs.readFile('./b.txt', 'utf8', function (err, data) {
if (err) return console.log(err);
logAllContent(data);
});
这样的方式虽然解决了问题,但是你不知道最终结果是在哪个异步函数中输出,而且你需要在所有的异步函数中都去调用打印方法。 promise方式大大简化: 借助promise.all()方法,不管哪个promise谁先完成,该方法会按照数组里面的顺序将结果返回。 let fs = require('fs');
let readFiles = (filePath)=>{
return new Promise(function(resolve,reject){
fs.readFile(filePath,'utf8', (err,data)=>{
if(err) return reject(err);
resolve(data);
})
})
}; Promise.all(
[readFiles('./a.txt'),
readFiles('./b.txt')]
).then(([data])=>{
console.log({data})
});
后续
借助Promise已经可以帮助我们很好解决异步编程的问题,但还不是那么的行云流水、一气呵成,我们更希望编写异步代码能够像写同步代码一样直观、简单。
在下一篇我们会讲些更好、更灵活的异步编程方案,敬请期待。获取资料、交流可加我微信:yejh9522 一起探讨学习。
撩课-Web架构师养成系列(第二篇)-async的更多相关文章
- 撩课-Web架构师养成系列第一篇
前言 Web架构师养成系列共15篇,每周更新一篇,主要分享.探讨目前大前端领域(前端.后端.移动端)企业中正在用的各种成熟的.新的技术.部分文章也会分析一些框架的底层实现,让我们做到知其然知其所以然. ...
- WEB架构师成长系列索引
WEB架构师成长系列索引 http://www.cnblogs.com/seesea125/archive/2012/04/17/2453256.html
- Web 架构师的能力(转)
文/刘如鸿 最近和几个朋友在谈到时下流行的Web 2.0,也提到了其中最重要的角色——架构师.多方各有争执,不外乎是因为背景和视角的缘故,包括架构一词,本身就从建筑学借鉴而来,至于架构师,则可以 简单 ...
- WEB架构师成长之路-架构师都要懂哪些知识 转
Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...
- WEB架构师成长之路之三-架构师都要懂哪些知识
Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...
- WEB架构师成长之路 三
Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...
- 【转载】WEB架构师成长之路
本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路,如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序员 ...
- 架构师成长系列 | 从 2019 到 2020,Apache Dubbo 年度回顾与总结
作者 | 刘军(陆龟)Apache Dubbo PMC 本文整理自架构师成长系列 2 月 18 日直播课程. 关注"阿里巴巴云原生"公众号,回复 "218",即 ...
- 前端工程师技能之photoshop巧用系列第二篇——测量篇
× 目录 [1]测量信息 [2]实战 [3]注意事项 前面的话 前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇——测量篇 测量信息 在网页制作中需要 ...
随机推荐
- 利用CXF生成webservice客户端代码
一.CXF环境的配置 1.下载CXF的zip包. 2.解压.例如:D:\ITSoft\webserviceClientUtils\cxf\apache-cxf-2.7.17 3.配置环境变量:新建变量 ...
- 50余本中外Python电子教程及源码下载地址
链接:http://pan.baidu.com/s/1c0VTwsC 密码:hapu
- USB-Redirector-Technician 永久破解版(USB设备映射软件)
USB-Redirector-Technician 这个软件对于搞安卓刷机的人想必非常熟悉,淘宝破解版售价:38 一个的东西 除了远程刷机,用于映射一些小型设备是没问题的,只要网跟得上~ USB-Re ...
- 总结day04 ---- 列表的切片,增删改查,以及,相关方法, 元祖的使用方法
内容大纲 1 : 列表的索引 : 列表的切片 2 : 列表的增加内容 >1:append(char) >2:insert(index,char) >3:extend('可迭代对象' ...
- [转]iOS:批量导入图片和视频到模拟器的相册
IOS开发中我们经常会用到模拟器调试,模拟器有个主要的好处就是程序启动块,最重要的是如果没有证书的话,我们就只能在模拟器上调试了.使用模拟器调试时我们可能碰到需要从系统相册选择图片的情况,特别是做图片 ...
- vector类型介绍
一.vector类型简介 标准库:集合或动态数组,我们可以放若干对象放在里面. vector他能把其他对象装进来,也被称为容器 #include <iostream> #include & ...
- bzoj4842: [Neerc2016]Delight for a Cat
bzoj4842 这是一道网络流的题(大家都看出来了吧) 首先我们简化一下题目,选出最关键的部分(就是知道什么和要求什么,还有条件) 我们在这里把睡觉设为0,至少有t0时间在睡觉,把打隔膜设为1,至少 ...
- knova绘制矩形
效果: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- Developer Friendly | 基础设施即代码的事实标准Terraform已支持京东云!
Developer Friendly | 基础设施即代码的事实标准Terraform已支持京东云! Chef.Puppet.Ansible.SaltStack 都可以称为配置管理工具,这些工具的主要目 ...
- VS 代码自动对齐快捷键
全部代码代码自动对齐快捷键为 Ctrl + a(按后可松松手) + k(按后可松松手) + f