深入理解JS异步编程-Promise


Posted in Javascript onJune 03, 2019

前言

“JS 是基于单线程事件循环”的概念构建的,回调函数不会立即执行,由事件轮询去检测事件是否执行完毕,当执行完有结果后,将结果放入回调函数的参数中,然后将回调函数添加到事件队列中等待被执行。

同时也讲了回调函数的问题:

一是“回调地狱”,因为异步回调函数的特点:回调函数是作为异步函数的参数,一层一层嵌套,当嵌套过多,将使代码逻辑变得混乱,也无法做好错误捕捉和处理(只能在回调函数内部 try catch)。

二是回调的执行方式不符合自然语言的线性思维方式,不容易被理解。

三是控制反转(控制权在其他人的代码上),假如异步函数是别人提供的库,我们把回调函数传进去,我们并不能知道异步函数在调用回调函数之外做了什么事情。

func1(() => {
func2(() => {
func3(() => {
func4(() => {
try {
...
} catch (err){
...
}
})
});
});
});

一、Promise 原理

首先,Promise 中文翻译为“承诺”, 是 JavaScript 的一种对象,表示承诺终将返回一个结果,无论成功还是失败。
Promise 有三个状态:等待中(pending),完成(fullfilled),失败(rejected), Promise 的设计具有原子性,状态一旦从 pending 状态转换为 fullfilled 状态或者 rejected 状态后,将不能被改变。

深入理解JS异步编程-Promise

var promise1 = new Promise((resolve, reject) => {
console.log("Promise 构造器会立即执行");
setTimeout(function (){
if(true) {
resolve("完成");
} else {
reject("失败");
}
}, 1000);
})
promise1
.then((result) => {
// do something
console.log(result);
return 1
// return Promise.resolve(1); // 返回一个决议为成功的 promise 实例
// return Promise.reject("error"); // 返回一个决议为拒绝的 Promise 实例
})
.then((result) => {
// .then() 方法会返回一个 promise, 完成调用的参数为前一个 promise 的返回值或者决议值。
// do other things
console.log(result);
throw new Error("错误") // 抛出错误是隐式拒绝
})
.catch((error) => {
// 捕捉错误
console.log(error)
})
.then(() => {
// 还能继续执行!
})
.finally(() => {
// always do somethings
console.log("finally!")
})

二、Promise 的优势

1.链式调用

Promise 使用 then 方法后还会返回一个新的 Promise 对象,便于我们传递状态数据,同时链式写法接近于同步写法,更符合线性思维。

2.错误捕捉

相比回调函数的错误无法在外部捕捉的问题,Promise 能够为一连串的异步调用提供错误处理。

3.控制反转再反转

由于第三方提供的异步函数,无法保证回调函数如何被执行,但是 Promise 的特点,能够保证异步函数只能被 resolve 一次,以及始终以异步的形式执行代码。

4.可以利用 Promise.all 和 Promise.race 来解决 Promise 始终未决议和并行 Promise 嵌套的问题

三、Promise 的不足

1.每个 .then() 都是一个独立的作用域

加入有很多个 .then() 方法,就会创建很多个独立的作用域,那么将只能通过外面包裹一层函数作用域的闭包来共享状态数据

2.无法取消单个 .then()

当 Promise 链中任意一个 .then() 方法中有语句执行错误后,尽管经过 catch 方法的错误处理,还是并不会中断整个 Promise 链的执行。

3.无法得知进度

由于 Promise 只能从 pending 到 fullfilled 或 rejected 状态,无法得知 pending 阶段的进度。

四、Promise 应用

// Promise 封装 ajax
function fetch(method, url, data){
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
var method = method || "GET";
var data = data || null;
xhr.open(method, url, true);
xhr.onreadystatechange = function() {
if(xhr.status === 200 && xhr.readyState === 4){
resolve(xhr.responseText);
} else {
reject(xhr.responseText);
}
}
xhr.send(data);
})
}
// 使用
fetch("GET", "/some/url.json", null)
.then(result => {
console.log(result);
})
// 封装 nodejs error first 风格回调
function readFile(url) {
return new Promise((resolve, reject) => {
fs.readFile(url,'utf8', (err, data) => {
if(err) {
reject(err);
return;
}
resolve(data)
}) 
})
}

五、总结

Promise 是 ES6 提出的简化异步流程控制新规范,强调异步任务的完成状态且具有原子性,这使得我们的代码更容易追踪和维护。Promise 在事件轮询中属于异步事件队列中的微任务,而微任务总是一次性全部执行,而宏任务是每轮轮询执行一个。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript编程起步(第三课)
Feb 27 Javascript
js 创建书签小工具之理论
Feb 25 Javascript
js实现双向链表互联网机顶盒实战应用实现
Oct 28 Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 Javascript
JavaScript使用addEventListener添加事件监听用法实例
Jun 01 Javascript
JavaScript中getUTCSeconds()方法的使用详解
Jun 11 Javascript
JS+CSS实现的经典圆角下拉菜单效果代码
Oct 21 Javascript
使用Jasmine和Karma对AngularJS页面程序进行测试
Mar 05 Javascript
xcode中获取js文件的路径方法(推荐)
Nov 05 Javascript
基于jQuery实现顶部导航栏功能
Dec 27 Javascript
vue单页缓存方案分析及实现
Sep 25 Javascript
JS实现公告上线滚动效果
Jan 10 Javascript
模块化react-router配置方法详解
Jun 03 #Javascript
react 组件传值的三种方法
Jun 03 #Javascript
angular使用md5,CryptoJS des加密的方法
Jun 03 #Javascript
Node.js 的 GC 机制详解
Jun 03 #Javascript
微信小程序蓝牙连接小票打印机实例代码详解
Jun 03 #Javascript
react-native滑动吸顶效果的实现过程
Jun 03 #Javascript
vue-cli 3 全局过滤器的实例代码详解
Jun 03 #Javascript
You might like
执行、获取远程代码返回:file_get_contents 超时处理的问题详解
2013/06/25 PHP
php 如何获取数组第一个值
2013/08/06 PHP
PHP四舍五入精确小数位及取整
2014/01/14 PHP
php实现文件下载实例分享
2014/06/02 PHP
支持中文、字母、数字的PHP验证码
2015/05/04 PHP
Yii框架用户登录session丢失问题解决方法
2017/01/07 PHP
如何优雅的使用 laravel 的 validator验证方法
2018/11/11 PHP
jquery异步请求实例代码
2011/06/21 Javascript
不提示直接关闭网页窗口的JS示例代码
2013/12/17 Javascript
Ajax请求在数据量大的时候出现超时的解决方法
2014/02/27 Javascript
jQuery树形插件jquery.simpleTree.js用法分析
2016/09/05 Javascript
JavaScript实现Java中Map容器的方法
2016/10/09 Javascript
JavaScript中定义对象原型的两种使用方法
2016/12/15 Javascript
JS实现仿PS的调色板效果完整实例
2016/12/21 Javascript
ES5 ES6中Array对象去除重复项的方法总结
2017/04/27 Javascript
小发现之浅谈location.search与location.hash的问题
2017/06/23 Javascript
JS验证输入的是否是数字及保留几位小数问题
2018/05/09 Javascript
使用淘宝镜像cnpm安装Vue.js的图文教程
2018/05/17 Javascript
在vue中使用G2图表的示例代码
2019/03/19 Javascript
微信小程序连续签到7天积分获得功能的示例代码
2020/08/20 Javascript
JavaScript实现点击出现子菜单效果
2021/02/08 Javascript
Python内置函数reversed()用法分析
2018/03/20 Python
Python查看微信撤回消息代码
2018/06/07 Python
对Python中数组的几种使用方法总结
2018/06/28 Python
Python实现基于PIL和tesseract的验证码识别功能示例
2018/07/11 Python
详解Django-restframework 之频率源码分析
2019/02/27 Python
django的分页器Paginator 从django中导入类
2019/07/25 Python
Python 如何实现数据库表结构同步
2020/09/29 Python
css3的focus-within选择器的使用
2020/05/11 HTML / CSS
公务员综合考察材料
2014/02/01 职场文书
中班开学寄语
2014/04/04 职场文书
房屋委托书范本
2014/04/04 职场文书
《放小鸟》教学反思
2014/04/20 职场文书
小学语文课后反思精选
2014/04/25 职场文书
机关保密承诺书
2014/06/03 职场文书
使用Apache Camel表达REST服务的方法
2022/06/10 Servers