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之更有效率的字符串替换
Aug 02 Javascript
JavaScript实现N皇后问题算法谜题解答
Dec 29 Javascript
在线所见即所得HTML编辑器的实现原理浅析
Apr 25 Javascript
JavaScript函数的一些注意要点小结及js匿名函数
Nov 10 Javascript
浅析jquery unbind()方法移除元素绑定的事件
May 24 Javascript
arcgis for js 修改infowindow样式的方法
Nov 02 Javascript
解决ionic和angular上拉加载的问题
Aug 03 Javascript
详解vue-cli项目中用json-sever搭建mock服务器
Nov 02 Javascript
vue中实现左右联动的效果
Jun 22 Javascript
微信小程序五子棋游戏的悔棋实现方法【附demo源码下载】
Feb 20 Javascript
element 中 el-menu 组件的无限极循环思路代码详解
Apr 26 Javascript
JavaScript异步操作中串行和并行
Nov 20 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 发送带附件邮件示例
2014/01/23 PHP
php中注册器模式类用法实例分析
2015/11/03 PHP
微信开发之获取JSAPI TICKET
2017/07/07 PHP
Laravel中服务提供者和门面模式的入门介绍
2017/11/06 PHP
PHP PDOStatement::fetchAll讲解
2019/01/31 PHP
关于laravel 子查询 & join的使用
2019/10/16 PHP
Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
2019/10/25 PHP
YII2框架中日志的配置与使用方法实例分析
2020/03/18 PHP
javascript 事件绑定问题
2011/01/01 Javascript
jQuery插件开发基础简单介绍
2013/01/07 Javascript
谈谈JavaScript中的函数与闭包
2013/04/14 Javascript
javaScript实现可缩放的显示区效果代码
2015/10/26 Javascript
jquery输入数字随机抽奖特效的简单实现代码
2016/06/10 Javascript
Angular中响应式表单的三种更新值方法详析
2017/08/22 Javascript
node.js中fs文件系统目录操作与文件信息操作
2018/02/24 Javascript
ES6学习笔记之map、set与数组、对象的对比
2018/03/01 Javascript
webpack4 CSS Tree Shaking的使用
2018/09/03 Javascript
createObjectURL方法实现本地图片预览
2019/09/30 Javascript
jquery实现掷骰子小游戏
2019/10/24 jQuery
用vue 实现手机触屏滑动功能
2020/05/28 Javascript
JS图片懒加载技术实现过程解析
2020/07/27 Javascript
[01:52]2014DOTA2西雅图邀请赛 V社开大会你不知道的小秘密
2014/07/08 DOTA
调试Python程序代码的几种方法总结
2015/04/28 Python
Python中的变量和作用域详解
2016/07/13 Python
Python+Turtle动态绘制一棵树实例分享
2018/01/16 Python
Python 通过requests实现腾讯新闻抓取爬虫的方法
2019/02/22 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
python中如何设置代码自动提示
2020/07/15 Python
Notino法国:购买香水和化妆品
2019/04/15 全球购物
REISS美国官网:伦敦最受欢迎的时尚品牌
2019/08/16 全球购物
大四学年自我鉴定
2013/11/13 职场文书
巾帼文明岗申报材料
2014/05/01 职场文书
室内设计专业毕业生求职信
2014/05/02 职场文书
马丁路德金演讲稿
2014/05/19 职场文书
党的群众路线教育实践活动个人整改方案
2014/10/25 职场文书
css中z-index: 0和z-index: auto的区别
2021/08/23 HTML / CSS