深入理解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 相关文章推荐
JQuery中getJSON的使用方法
Dec 13 Javascript
stream.js 一个很小、完全独立的Javascript类库
Oct 28 Javascript
JavaScript中数组对象的那些自带方法介绍
Mar 12 Javascript
解析window.open的使用方法总结
Jun 19 Javascript
ie8下修改input的type属性报错的解决方法
Sep 16 Javascript
JS实现带鼠标效果的头像及文章列表代码
Sep 27 Javascript
JavaScript实现倒计时跳转页面功能【实用】
Dec 13 Javascript
Node.js微信 access_token ( jsapi_ticket ) 存取与刷新的示例
Sep 30 Javascript
vue-router传参用法详解
Jan 19 Javascript
微信小程序实现用table显示数据库反馈的多条数据功能示例
May 07 Javascript
jquery UI实现autocomplete在获取焦点时得到显示列表功能示例
Jun 04 jQuery
vue实现动态表格提交参数动态生成控件的操作
Nov 09 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
别人整理的服务器变量:$_SERVER
2006/10/20 PHP
PHP下的Oracle客户端扩展(OCI8)安装教程
2014/09/10 PHP
php实现头像上传预览功能
2017/04/27 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
如何实现iframe(嵌入式帧)的自适应高度
2006/07/26 Javascript
jQuery 页面 Mask实现代码
2010/01/09 Javascript
JAVASCRIPT模式窗口中下载文件无法接收iframe的流
2013/10/11 Javascript
js 阻止子元素响应父元素的onmouseout事件具体实现
2013/12/23 Javascript
bootstrap data与jquery .data
2014/07/07 Javascript
HTML5 Shiv完美解决IE(IE6/IE7/IE8)不兼容HTML5标签的方法
2015/11/25 Javascript
JS+CSS实现鼠标经过弹出一个DIV框完整实例(带缓冲动画渐变效果)
2016/03/25 Javascript
Javascript OOP之面向对象
2016/07/31 Javascript
教你JS中的运算符乘方、开方及变量格式转换
2016/08/09 Javascript
js 判断各种数据类型的简单方法(推荐)
2016/08/29 Javascript
javaScript canvas实现(画笔大小 颜色 橡皮的实例)
2017/11/28 Javascript
解决vue+element 键盘回车事件导致页面刷新的问题
2018/08/25 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
微信小程序textarea层级过高的解决方法
2019/03/04 Javascript
vue中组件的3种使用方式详解
2019/03/23 Javascript
Quasar Input:type="number" 去掉上下小箭头 实现加减按钮样式功能
2020/04/09 Javascript
基于vue中的scoped坑点解说
2020/09/04 Javascript
[01:24]2014DOTA2 TI第二日 YYF表示这届谁赢都有可能
2014/07/11 DOTA
Python显示进度条的方法
2014/09/20 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
对python3 sort sorted 函数的应用详解
2019/06/27 Python
超简单的Python HTTP服务
2019/07/22 Python
pandas的to_datetime时间转换使用及学习心得
2019/08/11 Python
Python异常原理及异常捕捉实现过程解析
2020/03/25 Python
基于html5 DeviceOrientation 实现微信摇一摇功能
2015/09/25 HTML / CSS
YesStyle美国/全球:购买亚洲时装、美容化妆品和生活百货
2017/01/16 全球购物
KELLER SPORTS荷兰:在线订购最好的运动产品
2020/10/13 全球购物
C++如何引用一个已经定义过的全局变量
2014/08/25 面试题
仓库规划计划书
2014/04/28 职场文书
2014年城管个人工作总结
2014/12/08 职场文书
学校2016年全国助残日活动总结
2016/04/01 职场文书
pytorch损失反向传播后梯度为none的问题
2021/05/12 Python