自己动手实现一个Promise
栏目: JavaScript · 发布时间: 5年前
内容简介:Promise 对象是一个代理对象,被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象一个 Promise有以下几种状态:
Promise基本用法
Promise 对象是一个代理对象,被代理的值在Promise对象创建时可能是未知的。
它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
一个 Promise有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。 fulfilled: 意味着操作成功完成。 rejected: 意味着操作失败。
pending 状态的 Promise 对象可能触发fulfilled 状态并传递一个值给相应的状态处理方法,也可能触发失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回promise 对象, 所以它们可以被链式调用。
var promise1 = new Promise(function(resolve, reject) { setTimeout(function() { resolve('foo'); }, 300); }); promise1.then(function(value) { console.log(value); // expected output: "foo" }); console.log(promise1); // expected output: [object Promise]
Promise/A+
Promise的实现
- Promise是通过new创建的,可以通过构造函数模式或者是ES6的class来实现,这儿选择构造函数的方式来实现Promise,首先先完成一个简易版本的Promise。
function Promise(exector) { var _this = this this.status = 'pending' this.value = undefined try { exector(resolve, reject) }catch(e) { reject(e) } function resolve(value) { if(_this.status === 'pending') { _this.status = 'fulfilled' _this.value = value } } function reject(value) { if(_this.status === 'pending') { _this.status = 'rejected' _this.value = value } } } Promise.prototype.then = function(resolveCallback, rejectCallback) { if(this.status === 'fulfilled') { resolve(this.value) } if(this.status === 'rejected') { reject(this.value) } } new Promise((resolve, reject)=> { resolve('1') }).then((data)=> { console.log('resolve' + data) }, (data)=> { console.log('reject' + data) }) //resolve1 new Promise((resolve, reject)=> { setTimeout(()=> { resolve('1') }, 1000) }).then((data)=> { console.log('resolve' + data) }, (data)=> { console.log('reject' + data) }) //无法正常输出
上面这个promise中resolve和reject在同步的情况下都能正常输出,但是现在却不支持异步,因为在异步的时候调用then的时候状态还是'pending',所以resolve/reject并不能如期执行。
这个时候就需要一个存放后续调用事件的数组,当异步函数执行完毕后再执行数组中的函数。
改进后异步方法可以正常运行:
function Promise(exector) { var _this = this this.status = 'pending' this.value = undefined this.resolveList = [] this.rejectList = [] try { exector(resolve, reject) }catch(e) { reject(e) } function resolve(value) { if(_this.status === 'pending') { _this.status = 'fulfilled' _this.value = value _this.resolveList.forEach(item=> { item(_this.value) _this.resolveList.shift() }) } } function reject(value) { if(_this.status === 'pending') { _this.status = 'rejected' _this.value = value _this.rejectList.forEach(item=> { item(_this.value) _this.rejectList.shift() }) } } } Promise.prototype.then = function(resolveCallback, rejectCallback) { if(this.status === 'fulfilled') { resolve(this.value) } if(this.status === 'rejected') { reject(this.value) } if(this.status === 'pending') { this.resolveList.push(resolveCallback) this.rejectList.push(rejectCallback) } } new Promise((resolve, reject)=> { setTimeout(()=> { resolve('1') }, 1000) }).then((data)=> { console.log('resolve' + data) }, (data)=> { console.log('reject' + data) })
链式调用
我们可以注意到Promise是可以链式调用的,这就需要then的方法返回一个Promise对象。
下面是一个链式调用的简单例子:
let promise = new Promise((resolve, reject)=> { resolve(666) }) promise.then(data=> { console.log(data) return data + 1 }).then(data=> { console.log(data) }) //666 //667
在Promise链中返回Promise:
let promise1 = new Promise((resolve, reject)=> { resolve(666) }) let promise2 = new Promise((resolve, reject)=> { resolve(999) }) promise1.then(data=> { console.log(data) return promise2 }).then(data=> { console.log(data) }) //666 //999
关于这种写法需要注意的是,第二个完成处理程序被添加到第三个promise而不是return的promise2,上面的例子等价于:
let promise1 = new Promise((resolve, reject)=> { resolve(666) }) let promise2 = new Promise((resolve, reject)=> { resolve(999) }) let promise3 = promise1.then(data=> { console.log(data) return promise2 }) promise3.then(data=> { console.log(data) }) //666 //999
当异步的时候调用then函数的时候状态为pending,这个时候同样需要返回一个promise方便后续的链式调用。
所以修改为链式调用后的代码为:
function Promise(exector) { var _this = this this.status = 'pending' this.value = undefined this.resolveList = [] this.rejectList = [] try { exector(resolve, reject) }catch(e) { reject(e) } function resolve(value) { if(_this.status === 'pending') { _this.status = 'fulfilled' _this.value = value _this.resolveList.forEach(item=> { item(_this.value) _this.resolveList.shift() }) } } function reject(value) { if(_this.status === 'pending') { _this.status = 'rejected' _this.value = value _this.rejectList.forEach(item=> { item(_this.value) _this.rejectList.shift() }) } } } Promise.prototype.then = function(resolveCallback, rejectCallback) { var _this = this if(this.status === 'fulfilled') { return new Promise((resolve, reject)=> { var result = resolveCallback(_this.value) if(result instanceof Promise) { result.then(resolve, reject) }else { resolve(result) } }) } if(this.status === 'rejected') { return new Promise((resolve, reject)=> { var result = rejectCallback(_this.value) if(result instanceof Promise) { result.then(resolve, reject) }else { reject(result) } }) } if(this.status === 'pending') { return new Promise((resolve, reject)=> { _this.resolveList.push(function() { var result = resolveCallback(_this.value) if(result instanceof Promise) { result.then(resolve, reject) }else { resolve(result) } }) _this.rejectList.push(function() { var result = rejectCallback(_this.value) if(result instanceof Promise) { result.then(resolve, reject) }else { reject(result) } }) }) } } new Promise((resolve, reject)=> { resolve(666) }).then((data)=> { console.log('resolve1:' + data) return 999 }).then((data)=> { console.log('resolve2:' + data) }) //resolve1: 666 //resolve2: 999 new Promise((resolve, reject)=> { resolve(666) }).then((data)=> { console.log('resolve1:' + data) return new Promise((resolve, reject)=> { resolve(999) }) }).then((data)=> { console.log('resolve2:' + data) }) //resolve1: 666 //resolve2: 999
基本的功能已经实现,下面开始实现Promise的all,race,resolve,reject方法,链式调用部分思路借鉴 Promise/A+规范的实现
Promise.all()
该方法只接受一个有多个受监听的Promise的可迭代对象(比如数组),只有当可迭代对中所有Promise都被解决后才会返回resolve,如果参数中 promise 有一个失败,此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
Promise.all = function(iterable) { return new Promise((resolve, reject) => { let result = [] for(const item of iterable) { item.then(data => { result.push(data) }, reason=> { result = reason return }) } resolve(result) }) } //下面是测试用例 let p1 = new Promise((resolve, reject) => { resolve(666) }) let p2 = new Promise((resolve, reject) => { resolve(888) }) let p3 = new Promise((resolve, reject) => { resolve(999) }) let p6 = new Promise((resolve, reject) => { reject(222) }) let p4 = Promise.all([p1, p2, p3]) p4.then(data => { console.log(data) }) //[666, 888, 999] let p7 = Promise.all([p1, p3, p6]) p7.then(data => { console.log(data) }) //222
Promise.race()
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
Promise.race = function(iterable) { return new Promise((resolve, reject) => { for(const item of iterable) { item.then(data => { resolve(data) }, reason=> { reject(reson) }) } }) } //测试用例 var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); }); var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'two'); }); Promise.race([p1, p2]).then(function(value) { console.log(value); // Both resolve, but promise2 is faster }); //two
Promise.resolve()
Promise.resolve = function(data) { return new Promise((resolve, reject) => { resolve(data) }) } //测试用例 var p1 = Promise.resolve(123); p1.then(function(value) { console.log(value); }); //123
Promise.reject()
Promise.reject(reason)方法返回一个带有拒绝原因reason参数的Promise对象。
Promise.resolve = function(data) { return new Promise((resolve, reject) => { reject(data) }) }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 动手用CUDA实现CNN
- LeetCode146 动手实现LRU算法
- 自己动手实现神经网络分词模型
- 自己动手实现一个简单的React
- 动手造轮子:实现简单的 EventQueue
- 动手造轮子:基于 Redis 实现 EventBus
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。