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 相关文章推荐
JS解析XML的实现代码
Nov 12 Javascript
使用非html5实现js板连连看游戏示例代码
Sep 22 Javascript
输入框过滤非数字的js代码
Sep 18 Javascript
AngularJS  $on、$emit和$broadcast的使用
Sep 05 Javascript
AngularJs 动态加载模块和依赖
Sep 15 Javascript
JS制作适用于手机和电脑的通知信息效果
Oct 28 Javascript
vue自定义filters过滤器
Apr 26 Javascript
JavaScript实现一个简易的计算器实例代码
May 10 Javascript
浅谈Three.js截图并下载的大坑
Nov 01 Javascript
JS字符串补全方法padStart()和padEnd()
May 27 Javascript
解决vue组件没显示,没起作用,没报错,但该显示的组件没显示问题
Sep 02 Javascript
JS代码编译器Monaco使用方法
Jun 11 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+ACCESS 文章管理程序代码
2010/06/21 PHP
PHP利用hash冲突漏洞进行DDoS攻击的方法分析
2015/03/26 PHP
PHP实现简单日历类编写
2020/08/28 PHP
cookie 最近浏览记录(中文escape转码)具体实现
2013/06/08 Javascript
基于mouseout和mouseover等类似事件的冒泡问题解决方法
2013/11/18 Javascript
jQuery不兼容input的change事件问题解决过程
2014/12/05 Javascript
jqueryUI里拖拽排序示例分析
2015/02/26 Javascript
jquery.cookie实现的客户端购物车操作实例
2015/12/24 Javascript
Bootstrap组件系列之福利篇几款好用的组件(推荐)
2016/06/23 Javascript
jQuery基于ajax操作json数据简单示例
2017/01/05 Javascript
Vue服务端渲染和Vue浏览器端渲染的性能对比(实例PK )
2017/03/31 Javascript
分享十三个最佳JavaScript数据网格库
2017/04/07 Javascript
vue-music关于Player播放器组件详解
2017/11/28 Javascript
vue mounted组件的使用
2018/06/18 Javascript
通过封装scroll.js 获取滚动条的值
2018/07/13 Javascript
Vue项目引发的「过滤器」使用教程
2019/03/12 Javascript
微信小程序如何调用json数据接口并解析
2019/06/29 Javascript
[38:21]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS Newbee
2018/03/31 DOTA
在Python中使用lambda高效操作列表的教程
2015/04/24 Python
python实现逻辑回归的方法示例
2017/05/02 Python
Python安装模块的常见问题及解决方法
2018/02/05 Python
Python SVM(支持向量机)实现方法完整示例
2018/06/19 Python
Python读取txt文件数据的方法(用于接口自动化参数化数据)
2018/06/27 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
Python的几种主动结束程序方式
2019/11/22 Python
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
编程用JAVA解析XML的方式
2013/07/07 面试题
女方回门宴答谢词
2014/01/14 职场文书
网络工程师职业规划
2014/02/10 职场文书
学校花圃的标语
2014/06/18 职场文书
2014校长四风问题对照检查材料思想汇报
2014/09/16 职场文书
2014年团支部工作总结
2014/11/17 职场文书
预备党员转正意见
2015/06/01 职场文书
信仰观后感
2015/06/03 职场文书
2015年初中教务处工作总结
2015/07/21 职场文书
股东出资协议书
2016/03/21 职场文书