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 相关文章推荐
让焦点自动跳转
Jul 01 Javascript
js控制表单奇偶行样式的简单方法
Jul 31 Javascript
判断复选框是否被选中的两种方法
Jun 04 Javascript
javascript写的异步加载js文件函数(支持数组传参)
Jun 07 Javascript
JavaScript中神奇的call()方法
Mar 12 Javascript
基于jquery实现放大镜效果
Aug 17 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
Dec 01 Javascript
javascript中call,apply,bind函数用法示例
Dec 19 Javascript
浅谈Node 调试工具入门教程
Mar 20 Javascript
详解webpack-dev-server 设置反向代理解决跨域问题
Apr 18 Javascript
大转盘抽奖小程序版 转盘抽奖网页版
Apr 16 Javascript
vue 移动端注入骨架屏的配置方法
Jun 25 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制作图型计数器的例子
2006/10/09 PHP
用PHP制作的意见反馈表源码
2007/03/11 PHP
一步一步学习PHP(4) php 函数 补充2
2010/02/15 PHP
php截取字符串函数substr,iconv_substr,mb_substr示例以及优劣分析
2014/06/10 PHP
php preg_match的匹配不同国家语言实例
2016/12/29 PHP
javascript 函数式编程
2007/08/16 Javascript
替代window.event.srcElement效果的可兼容性的函数
2009/12/18 Javascript
页面只有一个text的时候,回车自动submit的解决方法
2010/08/12 Javascript
微信分享的标题、缩略图、连接及描述设置方法
2014/10/14 Javascript
SuperSlide标签切换、焦点图多种组合插件
2015/03/14 Javascript
JavaScript操作DOM元素的childNodes和children区别
2015/04/01 Javascript
详解js几个绕不开的事件兼容写法
2017/08/30 Javascript
AjaxUpLoad.js实现文件上传
2018/03/05 Javascript
layui表格checkbox选择全选样式及功能的实例
2018/03/07 Javascript
浅析Vue 生命周期
2018/06/21 Javascript
详解vue中axios请求的封装
2019/04/08 Javascript
nodejs二进制与Buffer的介绍与使用
2019/07/11 NodeJs
Vue+ElementUI 中级联选择器Bug问题的解决
2020/07/31 Javascript
python妹子图简单爬虫实例
2015/07/07 Python
深入解析Python中的集合类型操作符
2015/08/19 Python
python 实现图片旋转 上下左右 180度旋转的示例
2019/01/24 Python
python画图的函数用法以及技巧
2019/06/28 Python
flask 实现token机制的示例代码
2019/11/07 Python
python的slice notation的特殊用法详解
2019/12/27 Python
Python生成器传参数及返回值原理解析
2020/07/22 Python
一款利用纯css3实现的超炫3D表单的实例教程
2014/12/01 HTML / CSS
html5使用canvas绘制太阳系效果
2014/12/15 HTML / CSS
创业计划书六个要素
2013/12/26 职场文书
竞选班长的演讲稿
2014/04/24 职场文书
刑事附带民事诉讼答辩状
2015/05/22 职场文书
呼啸山庄读书笔记
2015/06/29 职场文书
毕业晚宴祝酒词
2015/08/11 职场文书
2016年七夕爱情寄语
2015/12/04 职场文书
浅谈Redis在直播场景的实践方案
2021/04/27 Redis
postman中form-data、x-www-form-urlencoded、raw、binary的区别介绍
2022/01/18 HTML / CSS
Typescript类型系统FLOW静态检查基本规范
2022/05/25 Javascript