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 相关文章推荐
页面中iframe相互传值传参
Dec 13 Javascript
Jquery Ajax请求代码(2)
Jan 07 Javascript
Extjs NumberField后面加单位实现思路
Jul 30 Javascript
jQuery实现可用于博客的动态滑动菜单完整实例
Sep 17 Javascript
Bootstrap Paginator分页插件使用方法详解
May 30 Javascript
vue2.0结合DataTable插件实现表格动态刷新的方法详解
Mar 17 Javascript
JS获取当前地理位置的方法
Oct 25 Javascript
浅谈React深度编程之受控组件与非受控组件
Dec 26 Javascript
react-router v4如何使用history控制路由跳转详解
Jan 09 Javascript
JavaScript 判断iPhone X Series机型的方法
Jan 28 Javascript
详解vue-element Tree树形控件填坑路
Mar 26 Javascript
JS原形与原型链深入详解
May 09 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中的reflection反射机制测试例子
2014/08/05 PHP
如何用PHP做到页面注册审核
2017/03/02 PHP
laravel 实现登陆后返回登陆前的页面方法
2019/10/03 PHP
用JS剩余字数计算的代码
2008/07/03 Javascript
超酷的网页音乐播放器DewPlayer使用方法
2010/12/18 Javascript
js 手机号码合法性验证代码集合
2012/09/29 Javascript
文本框文本自动补全效果示例分享
2014/01/19 Javascript
Angularjs编写KindEditor,UEidtor,jQuery指令
2015/01/28 Javascript
jquery实现简单的轮换出现效果实例
2015/07/23 Javascript
javascript html实现网页版日历代码
2016/03/08 Javascript
JS+CSS3实现超炫的散列画廊特效
2016/07/16 Javascript
JavaScript中localStorage对象存储方式实例分析
2017/01/12 Javascript
jQuery插件HighCharts实现的2D对数饼图效果示例【附demo源码下载】
2017/03/09 Javascript
详解JS转换数值函数Number()、parseInt()、parseFloat()
2018/08/24 Javascript
详解angular2.x创建项目入门指令
2018/10/11 Javascript
vue导航栏部分的动态渲染实例
2019/11/01 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
[04:32]DOTA2著名解说配音敌法师 现场专访海涛怒切假腿
2013/12/20 DOTA
[00:57]辉夜杯战队访谈宣传片—VG
2015/12/25 DOTA
pymssql ntext字段调用问题解决方法
2008/12/17 Python
Python深度优先算法生成迷宫
2018/01/22 Python
python如何读写json数据
2018/03/21 Python
django加载本地html的方法
2018/05/27 Python
Python 忽略warning的输出方法
2018/10/18 Python
python如何保证输入键入数字的方法
2019/08/23 Python
PyQt5 如何让界面和逻辑分离的方法
2020/03/24 Python
解锁canvas导出图片跨域的N种姿势小结
2019/01/24 HTML / CSS
澳大利亚最便宜的网上药房:Chemist Warehouse
2020/01/30 全球购物
行政助理岗位职责
2013/11/10 职场文书
3.15国际消费者权益日主题活动活动总结
2014/03/16 职场文书
物流管理专业毕业生求职信
2014/03/23 职场文书
有关爱国演讲稿
2014/05/07 职场文书
投标文件签署授权委托书范本
2014/10/12 职场文书
2015年高三毕业班班主任工作总结
2015/10/22 职场文书
Memcached介绍及php-memcache扩展安装
2021/04/01 PHP
APP界面设计技巧和注意事项
2022/04/29 杂记