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 相关文章推荐
javascript拓展DOM操作 prependChild insertAfert
Nov 17 Javascript
js实现日期级联效果
Jan 23 Javascript
jQuery的ajax和遍历数组json实例代码
Aug 01 Javascript
利用jquery正则表达式在页面验证url网址输入是否正确
Apr 04 jQuery
JS中把函数作为另一函数的参数传递方法(总结)
Jun 28 Javascript
详解为Bootstrap Modal添加拖拽的方法
Jan 05 Javascript
详解angular分页插件tm.pagination二次触发问题解决方案
Jul 20 Javascript
不得不知的ES6小技巧
Jul 28 Javascript
详解webpack4.x之搭建前端开发环境
Mar 28 Javascript
JS前端知识点offset,scroll,client,冒泡,事件对象的应用整理总结
Jun 27 Javascript
VUE 实现动态给对象增加属性,并触发视图更新操作示例
Nov 29 Javascript
JS实现手写 forEach算法示例
Apr 29 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 404错误页面实现代码
2009/06/22 PHP
使用PHP curl模拟浏览器抓取网站信息
2013/10/28 PHP
用PHP实现弹出消息提示框的两种方法
2013/12/17 PHP
PHP中使用gettext解决国际化问题的例子(i18n)
2014/06/13 PHP
PHP读取大文件的多种方法介绍
2016/04/04 PHP
php修改数组键名的方法示例
2017/04/15 PHP
php实现mysql连接池效果实现代码
2018/01/25 PHP
Prototype 学习 Prototype对象
2009/07/12 Javascript
Javascript中获取对象的原型对象的方法小结
2015/02/25 Javascript
JS原型对象的创建方法详解
2016/06/16 Javascript
详解如何使用Node.js编写命令工具——以vue-cli为例
2017/06/29 Javascript
AngularJS ng-repeat指令及Ajax的应用实例分析
2017/07/06 Javascript
ActiveX控件的使用-js实现打印超市小票功能代码详解
2017/11/22 Javascript
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
微信小程序页面渲染实现方法
2019/11/06 Javascript
React中获取数据的3种方法及优缺点
2020/02/18 Javascript
bootstrap-table后端分页功能完整实例
2020/06/01 Javascript
[58:46]OG vs NAVI 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python线程的两种编程方式
2015/04/14 Python
儿童python练习实例
2018/05/27 Python
Django MEDIA的配置及用法详解
2019/07/25 Python
Python 实现毫秒级淘宝抢购脚本的示例代码
2019/09/16 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
Window系统下Python如何安装OpenCV库
2020/03/05 Python
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
2012/12/13 HTML / CSS
HTML 5 input placeholder 属性如何完美兼任ie
2014/05/12 HTML / CSS
canvas压缩图片以及卡片制作的方法示例
2018/12/04 HTML / CSS
斯洛伐克时尚服装网上商店:Cellbes
2016/10/20 全球购物
世界上最好的足球商店:Unisport
2019/03/02 全球购物
医学生实习自荐信
2013/10/01 职场文书
应届生服务员求职信
2013/10/31 职场文书
大学生冰淇淋店商业计划书
2014/01/14 职场文书
代办委托书怎样写
2014/04/08 职场文书
婚礼上证婚人致辞
2015/07/28 职场文书
CSS 新特性 contain控制页面的重绘与重排问题
2021/04/30 HTML / CSS
Java tomcat手动配置servlet详解
2021/11/27 Java/Android