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 相关文章推荐
基于JQuery的访问WebService的代码(可访问Java[Xfire])
Nov 19 Javascript
理解JSON:3分钟课程
Oct 28 Javascript
基于jquery的网站幻灯片切换效果焦点图代码
Sep 15 Javascript
javascript手工制作悬浮菜单
Feb 12 Javascript
浅谈window对象的scrollBy()方法
Jul 15 Javascript
简单实现兼容各大浏览器的js复制内容到剪切板
Sep 09 Javascript
Bootstrap页面布局基础知识全面解析
Jun 13 Javascript
vue filters的使用详解
Jun 11 Javascript
JavaScript中十种一步拷贝数组的方法实例详解
Apr 22 Javascript
layui实现form表单同时提交数据和文件的代码
Oct 25 Javascript
vue路由分文件拆分管理详解
Aug 13 Javascript
javascript实现简单留言板案例
Feb 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
多文件上传的例子
2006/10/09 PHP
PHP远程连接MYSQL数据库非常慢的解决方法
2008/07/05 PHP
xml在joomla表单中的应用详解分享
2012/07/19 PHP
php打开远程文件的方法和风险及解决方法
2013/11/12 PHP
php缩放gif和png图透明背景变成黑色的解决方法
2014/10/14 PHP
Ubuntu server 11.04安装memcache及php使用memcache来存储session的方法
2016/05/31 PHP
javascript+css 网页每次加载不同样式的实现方法
2009/12/27 Javascript
基于jquery的一行代码轻松实现拖动效果
2010/12/28 Javascript
输入框的字数时时统计—关于 onpropertychange 和 oninput 使用
2011/10/21 Javascript
JS如何将UTC格式时间转本地格式
2013/09/04 Javascript
js的onload事件及初始化按钮事件示例代码
2013/09/25 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
2014/01/28 Javascript
javascript验证身份证号
2015/03/03 Javascript
JavaScript用select实现日期控件
2015/07/17 Javascript
原生js配合cookie制作保存路径的拖拽
2015/12/29 Javascript
Angularjs中UI Router的使用方法
2016/05/14 Javascript
Bootstrap表单布局样式代码
2016/05/31 Javascript
JS代码实现电脑配置检测功能
2018/03/21 Javascript
jQuery实现表单动态添加与删除数据操作示例
2018/07/03 jQuery
脚手架vue-cli工程webpack的基本用法详解
2018/09/29 Javascript
使用vue-cli webpack 快速搭建项目的代码
2018/11/21 Javascript
Vue实现push数组并删除的例子
2019/11/01 Javascript
Python中获取网页状态码的两个方法
2014/11/03 Python
python查找指定具有相同内容文件的方法
2015/06/28 Python
Python线性拟合实现函数与用法示例
2018/12/13 Python
WIn10+Anaconda环境下安装PyTorch(避坑指南)
2019/01/30 Python
CSS3中设置3D变形的transform-style属性详解
2016/05/23 HTML / CSS
印度在线杂货店:bigbasket
2018/08/23 全球购物
植村秀加拿大官网:Shu Uemura加拿大
2019/09/03 全球购物
湖南卫视在线视频媒体平台:芒果TV
2019/10/30 全球购物
一些PHP的面试题
2015/05/06 面试题
干部下基层实施方案
2014/03/14 职场文书
学习雷锋倡议书
2014/04/15 职场文书
竞选班干部演讲稿300字
2014/08/20 职场文书
批评与自我批评范文
2014/10/15 职场文书
详解Redis实现限流的三种方式
2021/04/27 Redis