JS中Promise函数then的奥秘探究


Posted in Javascript onJuly 30, 2018

Promise概述

Promise对象是CommonJS工作组提出的一种规范,目的是为异步操作提供统一接口。

那么,什么是Promises?

首先,它是一个对象,也就是说与其他JavaScript对象的用法,没有什么两样;其次,它起到代理作用(proxy),充当异步操作与回调函数之间的中介。它使得异步操作具备同步操作的接口,使得程序具备正常的同步运行的流程,回调函数不必再一层层嵌套。

简单说,它的思想是,每一个异步任务立刻返回一个Promise对象,由于是立刻返回,所以可以采用同步操作的流程。这个Promises对象有一个then方法,允许指定回调函数,在异步任务完成后调用。

Promise的then方法可以接受前一个函数的执行结果,还可以保证另一个Promise的顺序执行,这到底是怎么做到的呢?

原理图(先上图)

JS中Promise函数then的奥秘探究

问题需求

如何保证多个 promise 顺序执行?

实例:

var f1 = function (){
 return new Promise(function (resolve, reject){
  setTimeout(function (){
   console.log("f1 ok!")
   resolve("f1 ok!");
  }, 1000)
 });
}
var f2 = function (){
 return new Promise(function (resolve, reject){
  setTimeout(function (){
   console.log("f2 ok!")
   resolve("f2 ok!");
  }, 3000)
 });
}
var f3 = function (){
 return new Promise(function (resolve, reject){
  setTimeout(function (){
   console.log("f3 ok!")
   resolve("f3 ok!");
  }, 2000)
 });
}

当然如果要并行的话,我们很容易想到 Promise.all 方法:

Promise.all([f1(), f2(), f3()]).then(function (data){
 console.log(data)
})
// f1 ok! 
// f3 ok! 
// f2 ok! 
// ["f1 ok!", "f2 ok!", "f3 ok!"]

如果要顺序执行:

f1().then(f2).then(f3)
// f1 ok!
// f2 ok!
// f3 ok!

//或者这样

function f(all) {
 var promise = Promise.resolve();
 all.forEach((p, index) => {
  promise = promise.then(p)
 })
}
f([f1, f2, f3])

那么问题来了,then是如何做到顺序执行的呢,参数既可以是一个普通函数,也可是是一个返回promise的函数?

then的奥秘

很多实现promise的库都比较复杂,如果自己实现的话,可以借鉴下面简单的代码:

Promise.prototype.then = function(onFulfilled, onRejected) {
 var promise = this;
 return new Promise(function(resolve, reject) {
  function handle(value) {
   var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;
   if (ret && typeof ret['then'] == 'function') {
    ret.then(function(value) {
     resolve(value);
    }, function(reason) {
     reject(reason);
    });
   } else {
    resolve(ret);
   }
  }
  function errback(reason) {
   reason = typeof onRejected === 'function' && onRejected(reason) || reason;
   reject(reason);
  }
  if (promise._status === 'PENDING') {
   promise._resolves.push(handle);
   promise._rejects.push(errback);
  } else if (promise._status === FULFILLED) { 
   callback(promise._value);
  } else if (promise._status === REJECTED) {
   errback(promise._reason);
  }
 });
}

重点在then的实现,看上述代码,每个then返回的是什么,是一个新的 Promise,一个新的 Promise,一个新的 Promise
第二个重点是,在内部又处理了一个 回调函数运行结果是 一个 promise的 判断,如果是那么等待这个promise运行结束才调用 resolve 更改状态,关键是resolve的调用时机,resolve的调用时机,才能够往下执行,这两步就是then函数的关键。
是不是 有点晕,请看最开始的图。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript的parseInt 进制问题
May 07 Javascript
javascript 当前日期加(天、周、月、年)
Aug 09 Javascript
JQUERY对单选框(radio)操作的小例子
Apr 25 Javascript
javascript实现在下拉列表中显示多级树形菜单的方法
Aug 12 Javascript
jQuery animate和CSS3相结合实现缓动追逐效果附源码下载
Apr 18 Javascript
微信小程序 数据封装,参数传值等经验分享
Jan 09 Javascript
Angular.js去除页面中显示的空行方法示例
Mar 30 Javascript
除Console.log()外更多的Javascript调试命令
Jan 24 Javascript
JavaScript实现计算多边形质心的方法示例
Jan 31 Javascript
浅析Proxy可以优化vue的数据监听机制问题及实现思路
Nov 29 Javascript
原生js+canvas实现下雪效果
Aug 02 Javascript
详解webpack的clean-webpack-plugin插件报错
Oct 16 Javascript
浅析java线程中断的办法
Jul 29 #Javascript
还不懂递归?读完这篇文章保证你会懂
Jul 29 #Javascript
如何在js代码中消灭for循环实例详解
Jul 29 #Javascript
Vue-cli3项目配置Vue.config.js实战记录
Jul 29 #Javascript
vue权限路由实现的方法示例总结
Jul 29 #Javascript
JS高级技巧(简洁版)
Jul 29 #Javascript
js运算符的一些特殊用法
Jul 29 #Javascript
You might like
PHP缩略图等比例无损压缩,可填充空白区域补充色
2011/06/10 PHP
求PHP数组最大值,最小值的代码
2011/10/31 PHP
php preg_filter执行一个正则表达式搜索和替换
2012/02/27 PHP
详解yii2实现分库分表的方案与思路
2017/02/03 PHP
javascript调试说明
2010/06/07 Javascript
jquery win 7透明弹出层效果的简单代码
2013/08/06 Javascript
原生js实现淘宝首页点击按钮缓慢回到顶部效果
2014/04/06 Javascript
node.js [superAgent] 请求使用示例
2015/03/13 Javascript
jQuery中使用each处理json数据
2015/04/23 Javascript
Bootstrap表单Form全面解析
2016/06/13 Javascript
微信JS接口大全
2016/08/25 Javascript
详解js中Json的语法与格式
2016/11/22 Javascript
vue-cli构建项目使用 less的方法
2017/10/04 Javascript
vue实现分页组件
2020/06/16 Javascript
解决mui框架中switch开关通过js控制开或者关状态时小圆点不动的问题
2019/09/03 Javascript
Vue实现附件上传功能
2020/05/28 Javascript
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
2020/12/25 Vue.js
Python实现拼接多张图片的方法
2014/12/01 Python
【Python】Python的urllib模块、urllib2模块批量进行网页下载文件
2016/11/19 Python
浅谈pandas用groupby后对层级索引levels的处理方法
2018/11/06 Python
Python设计模式之迭代器模式原理与用法实例分析
2019/01/10 Python
django 环境变量配置过程详解
2019/08/06 Python
keras 解决加载lstm+crf模型出错的问题
2020/06/10 Python
JavaScript+Canvas实现自定义画板的示例代码
2019/05/13 HTML / CSS
微软英国官方网站:Microsoft英国
2016/10/15 全球购物
洲际酒店集团英国官网:IHG英国
2019/07/10 全球购物
Hush Puppies澳大利亚官网:舒适的男女休闲和正装鞋
2019/08/24 全球购物
廉政承诺书
2015/01/19 职场文书
德能勤绩廉个人总结
2015/02/14 职场文书
2015年销售员工作总结范文
2015/04/07 职场文书
2019年入党思想汇报格式与要求
2019/06/25 职场文书
如何利用STAR法则制作留学文书?
2019/08/26 职场文书
Java常用工具类汇总 附示例代码
2021/06/26 Java/Android
PostGIS的安装与入门使用指南
2022/01/18 PostgreSQL
Java 死锁解决方案
2022/05/11 Java/Android
JavaScript架构localStorage特殊场景下二次封装操作
2022/06/21 Javascript