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 相关文章推荐
统一接口:为FireFox添加IE的方法和属性的js代码
Mar 25 Javascript
jquery api参考 visualjquery 中国线路 速度快
Nov 30 Javascript
js jquery验证银行卡号信息正则学习
Jan 21 Javascript
javascript特殊日历控件分享
Mar 07 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
Sep 14 Javascript
如何提高数据访问速度
Dec 26 Javascript
JavaScript结合HTML DOM实现联动菜单
Apr 05 Javascript
jQuery实现右侧抽屉式在线客服功能
Dec 25 jQuery
JavaScript DOM元素常见操作详解【添加、删除、修改等】
May 09 Javascript
浅谈vuex的基本用法和mapaction传值问题
Nov 08 Javascript
如何在postman中添加cookie信息步骤解析
Jun 30 Javascript
js实现磁性吸附的示例
Oct 26 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
redis+php实现微博(二)发布与关注功能详解
2019/09/23 PHP
基于jquery的模态div层弹出效果
2010/08/21 Javascript
jQuery判断元素是否是隐藏的代码
2011/04/24 Javascript
js之ActiveX控件使用说明 new ActiveXObject()
2014/03/03 Javascript
Javascript基础教程之数据类型转换
2015/01/18 Javascript
jQuery时间轴插件使用详解
2015/07/16 Javascript
如何防止JavaScript自动插入分号
2015/11/05 Javascript
JavaScript职责链模式概述
2016/09/17 Javascript
JS动态给对象添加属性和值的实现方法
2016/10/21 Javascript
10分钟掌握XML、JSON及其解析
2020/12/06 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
2016/11/12 Javascript
Angular.Js之Scope作用域的学习教程
2017/04/27 Javascript
微信小程序获取当前时间及星期几的实例代码
2020/09/20 Javascript
three.js中多线程的使用及性能测试详解
2021/01/07 Javascript
JavaScript实现4位随机验证码的生成
2021/01/28 Javascript
[03:14]DOTA2斧王 英雄基础教程
2013/11/26 DOTA
[02:05]2014DOTA2西雅图邀请赛 老队长全明星大猜想谁不服就按进显示器
2014/07/08 DOTA
python列出目录下指定文件与子目录的方法
2015/07/03 Python
Python编程实现二分法和牛顿迭代法求平方根代码
2017/12/04 Python
Python内置模块hashlib、hmac与uuid用法分析
2018/02/12 Python
解决python 自动安装缺少模块的问题
2018/10/22 Python
修改 CentOS 6.x 上默认Python的方法
2019/09/06 Python
python生成xml时规定dtd实例方法
2020/09/21 Python
Pytorch实验常用代码段汇总
2020/11/19 Python
python实现简单的井字棋游戏(gui界面)
2021/01/22 Python
详解python第三方库的安装、PyInstaller库、random库
2021/03/03 Python
使用spring mvc+localResizeIMG实现HTML5端图片压缩上传的功能
2016/12/16 HTML / CSS
微软香港官网及网上商店:Microsoft HK
2016/09/01 全球购物
公司试用期员工自我评价
2014/09/17 职场文书
民主生活会整改措施(党员)
2014/09/18 职场文书
2014年政务公开工作总结
2014/12/09 职场文书
致青春观后感
2015/06/09 职场文书
房地产置业顾问工作总结
2015/10/23 职场文书
助学金申请书该怎么写?
2019/07/16 职场文书
python操作xlsx格式文件并读取
2021/06/02 Python
数据设计之权限的实现
2022/08/05 MySQL