简述异步编程&Promise&异步函数
前言:文章由本人在学习之余总结巩固思路,不足之前还请指出。
一.异步编程
首先我们先简单来回顾一下同步API和异步API的概念
1.同步API:只有当前的API执行完成之前,才会执行下一个API
例:
- console.log(‘first');
- console.log('last);
- 结果:
- first
- last
2.异步API:当前API的执行不会阻塞后续代码的执行
例:
- console.log('first');
- setTimeout(
- () => { console.log('last');
- }, 2000);
- console.log('middle');
- 结果:
- first
- middle
- last
执行顺序分析:
首先脚本会先执行同步代码,这时有一个同步代码区,按着从上到下的顺序进行。当所有的同步代码执行完成之后,再进入异步代码区查找是否有异步代码,并开始执行,执行完之后,调用对应的回调函数。
拿例子中的计时器来说,该异步函数每2秒都会重新调用一次。
注意:即使是计时器的时间设置为0,它任是一个异步API,不会随着同步一起执行。
3.Node.js中的异步API
- fs.readFile('./demo.txt', (err, result) => {});
当硬盘读取了文件之后,调用后方的回调函数;
但这个时候,我们有了一个需求,依次读取A,B,C三个文件。由于文件大小不一定是我们知道的,所以读取,查找的速度我们也并不知道。
按照同步的思路来写的话:
- fs.readFile('./1.txt', 'utf8', (err, result1) => {console.log(result1)});
- fs.readFile('./2.txt', 'utf8', (err, result2) => {console.log(result2)});
- fs.readFile('./3.txt', 'utf8', (err, result3) => {console.log(result3)});
结果未必如我们所愿。
这时我们也许会想到一个办法,既然该API是异步API,我们把各个API嵌套起来,这样不久可以依次执行了?
- fs.readFile('./1.txt', 'utf8', (err, result1) => {
- console.log(result1)
- fs.readFile('./2.txt', 'utf8', (err, result2) => {
- console.log(result2)
- fs.readFile('./3.txt', 'utf8', (err, result3) => {
- console.log(result3)
- })
- })
- });
emmm....确实可以,但他的缺点也能预料到:这里只有三个文件,可能不易看出其劣势,但是如果是300个呢?代码的可读性将大幅度降低,维护的难度相应提高,这是我们不愿意看到的。
这一现象,我们称其为回调地狱(callbackhell)。进来了就si里面了。
解决的办法当然也有,这时该轮到我们的Promise登场了。
二.Promise
Promise出现的目的是解决Node.js异步编程中回调地狱的问,它是一个构造函数,我们要用new Promise的方法调用。
我们先来简单地介绍一下Promise。
- let promise = new Promise((resolve, reject) => {});
- Promise的参数为一个匿名回调函数,其中reslove,reject也是回调函数,他能将异步API的执行和结果进行分离,reslove对应着result(正常思路下)当fs有返回结果的时候,我们可以将其通过回调函数的方式将其发送到外面,
同理,当fs出现错误的时候,我们可以将其发送到外面进行处理。这里要用到Promise下面的两个方法promise.then()&promise.catch(),分别用来对结果和错误信息进行处理。- 我们结合实例来分析这些回调函数。
- let promise = new Promise((resolve, reject) => {
- fs.readFile('./1.txt', 'utf8', (err, result) => {
- if (err != null) {
- reject(err);
相当于执行then里面的回调函数- }else {
- resolve(result);
相当于执行catch里面的回调函数- }
- });
- });
promise.then((result) => {
console.log(result);
})
.catch((err)=> {
console.log(err);
})
- 用此方法来对我们之前的函数进行包装,分析一下,既然我们有三个异步API,我们则需要用三个Promise将他们包裹起来,我们需要让这三个promise依次执行,但是如果我们直接声明了一个变量等于promise的话就直接执行了,所以
这里我们用一个函数把他封装起来
- function p1 () {
- return new Promise ((resolve, reject) => {
- fs.readFile('./1.txt', 'utf8', (err, result) => {
- resolve(result)
- })
- });
- }
- function p2 () {
- return new Promise ((resolve, reject) => {
- fs.readFile('./2.txt', 'utf8', (err, result) => {
- resolve(result)
- })
- });
- }
- function p3 () {
- return new Promise ((resolve, reject) => {
- fs.readFile('./3.txt', 'utf8', (err, result) => {
- resolve(result)
- })
- });
- }
为了实现顺序调用,我们使用链式编程
- p1().then((r1)=> {
- console.log(r1);
- return p2();
- })
- .then((r2)=> {
- console.log(r2);
- return p3();
- })
- .then((r3) => {
- console.log(r3)
- })
注意:这里return 调用返回的结果我们可以参考MDN的解释
返回一个已经是接受状态的 Promise,那么 then
返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
这里看上去我们的代码的似乎比之前的嵌套关系更为复杂,这里就要引入我们的异步函数了。
3.异步函数
异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。
举一个简单的函数来看看他的用法
- // 1.在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
- // 2.异步函数默认的返回值是promise对象
- // 3.在异步函数内部使用throw关键字进行错误的抛出
- async function fn () {
这里我们发现我们不需要再new一个Promise再将其返回了- return 123; //正常的时候用return
- // throw '发生了一些错误';出错的时候throw
- }
- console.log(fn ())
- fn ()
- .then(function (data) {
- console.log(data);
- })
- .catch(function (err){
- console.log(err);
- })
- 那么如何让我们的函数有序地进行呢?这里我们不用再采用return嵌套,接下来就要用到await了
我们定义一个run函数
- // await关键字
- // 1.它只能出现在异步函数中
- // 2.await promise 它可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数
- async function run () {
- let r1 = await p1()
- let r2 = await p2()
- // await不能直接得到throw并赋值给r3这里我们采用catch试试
- let r3 = p3().catch(n => console.log(n));// p3
- console.log(r1)
- console.log(r2)
- console.log(r3 instanceof Promise)//ture
- // console.log(r3)
- }
- 这样就能实现我们的按顺序执行了
此处r3的值是我在记笔记的时候发现await并不直接接受reject的Promise,所以做了个输出的尝试,随意看看就好- run();
新手一枚,大家有啥好的想法或者问题欢迎一起讨论
简述异步编程&Promise&异步函数的更多相关文章
- 简单实现异步编程promise模式
本篇文章主要介绍了异步编程promise模式的简单实现,并对每一步进行了分析,需要的朋友可以参考下 异步编程 javascript异步编程, web2.0时代比较热门的编程方式,我们平时码的时候也或多 ...
- 前端分享----JS异步编程+ES6箭头函数
前端分享----JS异步编程+ES6箭头函数 ##概述Javascript语言的执行环境是"单线程"(single thread).所谓"单线程",就是指一次只 ...
- 异步编程——promise
异步编程--promise 定义 Promise是异步编程的一个解决方案,相比传统的解决方法--回调函数,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,也使得代码结构更为清晰,便于维 ...
- 异步编程promise
异步编程发展 异步编程经历了 callback.promise.async/await.generator四个阶段,其中promise和async/await使用最为频繁,而generator因为语法 ...
- C#复习笔记(5)--C#5:简化的异步编程(异步编程的基础知识)
异步编程的基础知识 C#5推出的async和await关键字使异步编程从表面上来说变得简单了许多,我们只需要了解不多的知识就可以编写出有效的异步代码. 在介绍async和await之前,先介绍一些基础 ...
- .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)
本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...
- 异步编程Promise/Deferred、多线程WebWorker
长期以来JS都是以单线程的模式运行的,而JS又通常应用在操作用户界面和网络请求这些任务上.操作用户界面时不能进行耗时较长的操作否则会导致界面卡死,而网络请求和动画等就是耗时较长的操作.所以在JS中经常 ...
- Javascript异步编程之一异步原理
本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...
- C#复习笔记(5)--C#5:简化的异步编程(异步编程的深入分析)
首先,阐明一下标题的这个“深入分析”起得很惭愧,但是又不知道该起什么名字,这个系列也主要是做一些复习的笔记,供自己以后查阅,如果能够帮助到别人,那自然是再好不过了. 然后,我想说的是异步方法的状态机真 ...
随机推荐
- stand up meeting 12/7/2015
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 ------------------ -- --------------------- --- PDF Rea ...
- 数据挖掘入门系列教程(十)之k-means算法
简介 这一次我们来讲一下比较轻松简单的数据挖掘的算法--K-Means算法.K-Means算法是一种无监督的聚类算法.什么叫无监督呢?就是对于训练集的数据,在训练的过程中,并没有告诉训练算法某一个数据 ...
- 详解 普通数组 —— Arrays类 与 浅克隆
我们在C语言中,编一些代码量规模比较大的程序,几乎都会用到 "数组" 或 "链表" ,但是,在本人之前的博文中,却对这两个知识点从未提到过,那么,本人将通过这篇 ...
- 小知识点:session的存放位置
在php.ini里的配置session.save_path是注释掉的,那么Seesion保存的路径在不同类型操作系统保存在什么位置? Linux: /tmp 或 /var/lib/php/sessio ...
- 《Spring In Action》阅读笔记之核心概念
DI 依赖注入:在xml中配置的bean之间的依赖关系就是依赖注入 AOP 面向切面编程:如在xml中定义某个方法为切点,然后配置在该切点(该方法)调用前后需要调用的方法,从而简化了代码并解耦. Sp ...
- MySQL之唯一索引、外键的变种、SQL语句数据行操作补充
0.唯一索引 unique对num进行唯一限制,表示num是独一无二的,uql是唯一索引名称 上面为联合索引:num和xx不能完全一样 1.外键的变种 a. 用户表和部门表 用户: 1 alex 1 ...
- MySQL 查询语句优化思路
query 语句的优化思路和原则主要提现在以下几个方面:1. 优化更需要优化的Query:2. 定位优化对象的性能瓶颈:3. 明确的优化目标:4. 从 Explain 入手:5. 多使用profile ...
- auth权限逻辑
下面本人为大家讲解一下如何实现auth权限, 第一步,新建Auth.php,复制下面的代码,把注释中的表都创建一下.把文件放到extend新建文件夹org放进去即可, <?php // +--- ...
- python学习02python入门二
学前须知:1.本文档有关内容均建立在python3.x版本上,python2.x已经成为历史,如有需要,文内会特别说明. 2.本文使用的编辑器多为架构在Windows上的pycharm,如需了解Lin ...
- linux awk 命令实用手册
0,简介 Linux awk 是一个实用的文本处理工具,它不仅是一款工具软件,也是一门编程语言.awk 的名称来源于其三位作者的姓氏缩写,其作者分别是Alfred Aho,Peter Weinberg ...