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中的变量是传值还是传址的?
Apr 19 Javascript
基于jquery实现点击左右按钮图片横向滚动
Apr 11 Javascript
Jquery选中或取消radio示例
Sep 29 Javascript
js输入框邮箱自动提示功能代码实现
Dec 10 Javascript
Javascript中call与apply的学习笔记
Sep 22 Javascript
javascript中Function类型详解
Apr 28 Javascript
bootstrap为水平排列的表单和内联表单设置可选的图标
Feb 15 Javascript
详细讲解如何创建, 发布自己的 Vue UI 组件库
May 29 Javascript
javascript数组元素删除方法delete和splice解析
Dec 09 Javascript
vue 动态生成拓扑图的示例
Jan 03 Vue.js
JavaScript 声明私有变量的两种方式
Feb 05 Javascript
vue代码分块和懒加载非必要资源文件
Apr 11 Vue.js
浅析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扩展介绍与开发教程
2010/08/19 PHP
php中实现xml与mysql数据相互转换的方法
2014/12/25 PHP
PHP关键特性之命名空间实例详解
2017/05/06 PHP
file控件选择上传文件确定后触发的js事件是哪个
2014/03/17 Javascript
jQuery实现的原图对比窗帘效果
2014/06/15 Javascript
CSS3,HTML5和jQuery搜索框集锦
2014/12/02 Javascript
jQuery中next方法用法实例
2015/04/24 Javascript
jQuery+css3实现文字跟随鼠标的上下抖动
2015/07/31 Javascript
Bootstrap Metronic完全响应式管理模板之菜单栏学习笔记
2016/07/08 Javascript
ReactNative-JS 调用原生方法实例代码
2016/10/08 Javascript
正则中的回溯定义与用法分析【JS与java实现】
2016/12/27 Javascript
解决vue里碰到 $refs 的问题的方法
2017/07/13 Javascript
jQuery常用选择器详解
2017/07/17 jQuery
Nuxt.js实战和配置详解
2019/08/05 Javascript
解决layer弹出层自适应页面大小的问题
2019/09/16 Javascript
java和js实现的洗牌小程序
2019/09/30 Javascript
JS实现放烟花效果
2020/03/10 Javascript
JS中作用域以及变量范围分析
2020/07/18 Javascript
vue 组件之间事件触发($emit)与event Bus($on)的用法说明
2020/07/28 Javascript
Python实现的自定义多线程多进程类示例
2018/03/23 Python
Python 计算任意两向量之间的夹角方法
2019/07/05 Python
浅谈keras中的目标函数和优化函数MSE用法
2020/06/10 Python
详解Python高阶函数
2020/08/15 Python
英国著名的药妆网站:Escentual
2016/07/29 全球购物
vue实现倒计时功能
2021/03/24 Vue.js
教师实习期自我鉴定
2013/10/06 职场文书
外贸业务员求职信范文
2013/12/12 职场文书
护士毕业生自我鉴定
2014/02/08 职场文书
代理人委托书
2014/08/01 职场文书
给上级领导的感谢信
2015/01/22 职场文书
物业工程部经理岗位职责
2015/04/09 职场文书
紧急迫降观后感
2015/06/15 职场文书
人身损害赔偿协议书
2016/03/22 职场文书
六年级上册《闻官军收河南河北》的教学设计
2019/11/15 职场文书
go原生库的中bytes.Buffer用法
2021/04/25 Golang
Python 全局空间和局部空间
2022/04/06 Python