Promise基础
前言:
ES2015将Promise引入语言规范,包括fetch等在内的API也构建在Promise之上。作为让js摆脱“回调地狱”的重要一环和众多框架中的重要基础设施之一,学习如何自己实现一个Promise插件依然是前端工程师晋级之路上很有意义的练习之一。
Promise规范:
在众多Promise规范中,最著名的就是A+规范:
在此规范中,promise被定义为一个带有then方法的object或function,具有pending(可转换为fulfilled或rejected),fulfilled(不可转换,需带有一个value),rejected(不可转换,需带有一个reason)三种状态。
then方法调用时接受成功和失败的回调:promise.then(onFulfilled, onRejected)。onFulfilled在promise被fulfill时调用一次,并传入value;onRejected在promise被reject时调用一次,传入reason。一个promise的then可以被多次调用,因此调用then需要返回promise。
Promise可以被resolve,resolve的传入值也可以是一个promise(thenable的对象)。正确解析promise链,处理其中的resolve、exception、handler的返回值等等是关键所在。
具体文档可见:https://promisesaplus.com/
自己实现Promise:
mmDeferred(https://github.com/RubyLouvre/mmDeferred)是一个优秀的遵循Promise/A+规范的Deffered库,我们就来仿造它看看如何写一个Deffered库。
Deferred函数:
function Deferred() {
var state = "pending", dirty = false // 定义状态state,dirty
function ok(x) { // 定义转换state为fulfilled的接口,返回传入的x
state = "fulfilled"
return x
}
function ng(e) {
state = "rejected" // 定义转换state为rejected的接口,抛出异常
throw e
}
...
}
接下来我们添加Deferred的返回,它将是一个thenable的对象:
var dfd = {
callback: { // 定义resolve与reject的callback
resolve: ok,
reject: ng,
},
dirty: function() {
return dirty
},
state: function() {
return state
},
promise: {
then: function() { // 定义接口then,接受onFulfilled,onRejected作为参数
return _post.apply(null, arguments)
},
_next: null // 每个thenable通过_next完成promise链的构成
}
}
最后我们将给dfd对象绑定resolve与reject对象并返回:
"resolve,reject".replace(/\w+/g, function(method) {
dfd[method] = function() {
var that = this, args = arguments
// promise链上的第一个回调需要异步触发,但剩余链上的回调需要同步触发
if (that.dirty()) {
_fire.call(that, method, args)
} else {
setTimeout(function() {
_fire.call(that, method, args)
}, 0);
}
}
})
return dfd
这里用到了两个闭包内的函数_post与_fire,我们来看看他们各自做了什么:
function _post() {
var index = -1, fns = arguments;
"resolve,reject".replace(/\w+/g, function(method) {
var fn = fns[++index];
if (typeof fn === "function") {
// promise链的头结点,回调需要异步触发
dirty = true
// 修改dfd的resolve与reject函数,绑定then函数传入的回调
dfd.callback[method] = function() {
try {
var value = fn.apply(this, arguments)
state = "fulfilled"
return value
} catch (err) {
state = "rejected"
return err
}
}
}
})
// 形成promise链
var deferred = dfd.promise._next = Deferred(mixin)
return deferred.promise;
}
function _fire(method, array) {
var next = "resolve", value
// 根据状态触发回调
if (this.state() === "pending") {
var fn = this.callback[method]
try {
value = fn.apply(this, array);
} catch (e) {//处理notify的异常
value = e
}
if (this.state() === "rejected") {
next = "reject"
}
array = [value]
}
// promise链依次触发
var nextDeferred = this.promise._next
if (Deferred.isPromise(value)) {
value._next = nextDeferred
} else {
if (nextDeferred) {
_fire.call(nextDeferred, next, array);
}
}
}
还有isPromise 函数:
Deferred.isPromise = function(obj) {
return !!(obj && typeof obj.then === "function");
};
以上便是简化的Deferred库实现,在原库中还有一些优化,比如Deferred可以接受一个对象,以扩展这个对象为thenable,以及在resolve和reject之外还定义了notify(同时增加notify状态,可以继续转化为fulfilled或者rejected状态)以及ensure(无论状态如何转换都会触发),定义了Deferred.all与Deferred.any等等。
Promise基础的更多相关文章
- promise 基础知识
promise 基础知识 proise:1.Promise是异步编程的一种解决方案,它有三种状态,分别是pending-进行中.resolved-已完成.rejected-已失败2.创建实例//met ...
- promise基础和进阶
本文不对Promise的做过深的解析,只对基础的使用方法,然后会记录一些promise的使用技巧,可以巧妙的解决异步的常见问题. 在过去一直理解的是解决了一直异步回调的坑,但是用了npm async之 ...
- Promise 基础学习
Promise 是ES6的特性之一,采用的是 Promise/A++ 规范,它抽象了异步处理的模式,是一个在JavaScript中实现异步执行的对象. 按照字面释意 Promise 具有"承 ...
- promise基础用法
/** * Created by liyinghao on 2016/11/6. */ const fs = require('fs'); /* * 新建一个Promise对象,Promise就是一个 ...
- JavaScript promise基础示例
const { info } = console // cooking function cook() { info('[COOKING] start cooking.') const p = new ...
- Promise编程基础
(一) Promise基础 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise是一个对象,从它可以获取异步操作的消 ...
- 前端基础进阶(十三):透彻掌握Promise的使用,读这篇就够了
Promise的重要性我认为我没有必要多讲,概括起来说就是必须得掌握,而且还要掌握透彻.这篇文章的开头,主要跟大家分析一下,为什么会有Promise出现. 在实际的使用当中,有非常多的应用场景我们不能 ...
- ES6的promise对象应该这样用
ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...
- 【JavaScript】JavaScript Promise 探微
http://www.html-js.com/article/Promise-translation-JavaScript-Promise-devil-details 原文链接:JavaScript ...
随机推荐
- FIFO 和 LRU 调度算法
在一个采用页式虚拟存储管理的系统中(字地址序列.页号.块号均从零开始编址),有一用户作业,它依次要访问的字地址序列是:15,128,300,388,246,402,223,142,360,267,若该 ...
- ARMs3c2440开发板挂接NFS服务
1.修改IP地址,使虚拟机,电脑PC机.开发板位于同一个网段,开发板网线与电脑网络接口连接,如PC:ip 192.168.0.112 255.255.255.0 虚拟机 192.168.0.8 255 ...
- HDU 1789 Doing Homework again(贪心)
在我上一篇说到的,就是这个,贪心的做法,对比一下就能发现,另一个的扣分会累加而且最后一定是把所有的作业都做了,而这个扣分是一次性的,所以应该是舍弃扣分小的,所以结构体排序后,往前选择一个损失最小的方案 ...
- HDU 1527 取石子游戏(威佐夫博弈)
基础威佐夫博弈,判断奇异局势即可,判断方式为k为两数之差绝对值,(sqrt(5) + 1) / 2 * k若等于两数小者则为奇异局势,也就是必败态. #include<stdio.h> # ...
- (中等) CF 311B Cats Transport,斜率优化DP。
Zxr960115 is owner of a large farm. He feeds m cute cats and employs p feeders. There's a straight r ...
- Oracle存储过程中如何使用游标
--本存储过程的功能:把test_tbl2中与test_tbl1中ID相同但salary不同的记录中的salary的值更新为test_tbl1中的salary的值--创建存储过程create or r ...
- iOS完美版的UIScrollView无缝循环:你值得一看
可以直接copy运行研究 .m头文件和声明的常量(宏和const) #import "ViewController.h" // UIScrollView的尺寸 const CGFl ...
- VS2012配置Cocos2d-x的问题
cocos2d-x老是配置不成功,解决方案参考:http://blog.csdn.net/yangjingui/article/details/9408007 完整配置流程: 1 下载,最好通过SVN ...
- mac和xcode快捷键
mac中: 1.怎么建立快捷方式 首先 按住option+command ,在用鼠标拖动目标文件到指定地点,先松开鼠标,然后在松开键盘
- 蘑菇街teamtalk简介
这几天在看蘑菇街实时通讯程序teamtalk的安卓端代码.现在对程序的大概情况进行简单的介绍. 蘑菇街的teamtalk开源项目包含了服务器端,Android客户端和iPhone客户端的程序.想要进行 ...