前言

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的更多相关文章

  1. 撩课-Web架构师养成系列第一篇

    前言 Web架构师养成系列共15篇,每周更新一篇,主要分享.探讨目前大前端领域(前端.后端.移动端)企业中正在用的各种成熟的.新的技术.部分文章也会分析一些框架的底层实现,让我们做到知其然知其所以然. ...

  2. WEB架构师成长系列索引

    WEB架构师成长系列索引 http://www.cnblogs.com/seesea125/archive/2012/04/17/2453256.html

  3. Web 架构师的能力(转)

    文/刘如鸿 最近和几个朋友在谈到时下流行的Web 2.0,也提到了其中最重要的角色——架构师.多方各有争执,不外乎是因为背景和视角的缘故,包括架构一词,本身就从建筑学借鉴而来,至于架构师,则可以 简单 ...

  4. WEB架构师成长之路-架构师都要懂哪些知识 转

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  5. WEB架构师成长之路之三-架构师都要懂哪些知识

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  6. WEB架构师成长之路 三

    Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...

  7. 【转载】WEB架构师成长之路

    本人也是coding很多年,虽然很失败,但也总算有点失败的心得,不过我在中国,大多数程序员都是像我一样,在一直走着弯路,如果想成为一个架构师,就必须走正确的路,否则离目标越来越远,正在辛苦工作的程序员 ...

  8. 架构师成长系列 | 从 2019 到 2020,Apache Dubbo 年度回顾与总结

    作者 | 刘军(陆龟)Apache Dubbo PMC 本文整理自架构师成长系列 2 月 18 日直播课程. 关注"阿里巴巴云原生"公众号,回复 "218",即 ...

  9. 前端工程师技能之photoshop巧用系列第二篇——测量篇

    × 目录 [1]测量信息 [2]实战 [3]注意事项 前面的话 前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇——测量篇 测量信息 在网页制作中需要 ...

随机推荐

  1. 【Oracle 12c】CUUG OCP认证071考试原题解析(35)

    35.choose the best answer View the Exhibit and examine the description of the EMPLOYEES table. Evalu ...

  2. P3357 最长k可重线段集问题 网络流

    P3357 最长k可重线段集问题 题目描述 给定平面 x-O-yx−O−y 上 nn 个开线段组成的集合 II,和一个正整数 kk .试设计一个算法,从开线段集合 II 中选取出开线段集合 S\sub ...

  3. IT项目中使用 json格式数据 保存项目配置信息, 在配置文件再读取json文件的内容进行赋值

    json格式小巧玲珑,适合做配置文件,特别是大型项目中, 可以将配置信息分类保存到不同的json文件中, 然后再在配置文件中读取配置文件的数据进行赋值, 这里以python为例进行说明: 假设在you ...

  4. [Swift]数组排序:sort和sorted

    sorted只返回一个数组的有序版本,不修改原数组. sort无返回值,只会修改原数组. 定义一个需要排序的数组,其包含元素.示例只初始化一个Int数组. var arr:[Int] = [Int]( ...

  5. Windows Server 2012 R2 部署DC及主辅DC

    背景信息: 资源组:hlmdcn DC1:windows Server 2012 R2 Datacenter, A2, hlmdc1, 10.8.0.4DC2:windows Server 2012 ...

  6. leetcode-292-Nim Game(搬石子)

    题目描述: You are playing the following Nim Game with your friend: There is a heap of stones on the tabl ...

  7. python里有意思的文件查找glob模块

    python标准库之glob介绍 glob 文件名模式匹配,不用遍历整个目录判断每个文件是不是符合. 1.通配符 星号(*)匹配零个或多个字符 import glob for name in glob ...

  8. 织梦dede解决“更新数据库archives表时出错"方法

    登陆dedecms网站管理后台,选择执行 sql命令工具,将下列命令执复制进去并执行多行执行,该问题就可以解决. alter table `idea_archives` ADD `voteid` me ...

  9. Cisco ASA 8.3前及8.3后版本Access-list 变化

    8.2及之前 access-list:源地址是真实IP地址,目的地址是映射地址packet-tracer:源地址为真实IP地址,目的地址为映射地址 8.3及之后access-list:源地址和目的地址 ...

  10. WP调用api

    private string GetText() { string resultString = string.Empty; HttpWebRequest request = HttpWebReque ...