Promise 大家都知道怎么用, 但是对于内部的原理很多人都不是很清楚
来看一个面试题: Promise的then 是怎么实现的
首先来分析一下then
来一个一个看吧
then是属于实例上的方法
Promise.prototype.then = function(){}
Promise.prototype.then = function(onFulfilled,onRejected){}
Promise.prototype.then = function(onFulfilled,onRejected){
return new Promise(function(resolve,reject){
// 代码省略
})
}
要实现promise链式 返回的必须是一个Promise 再由于status 改变状态了不能再变 所以需要第二个.... 第N个promise 调用新的resolve
then执行要执行Promise onFulfilled 或者 onRejected 方法
Promise.prototype.then = function(onFulfilled,onRejected){
var self = this; // 保存当前上下文
return new Promise(function(resolve,reject){
if(self.status === 'resolved'){
onFulfilled(self.res)
}
if(self.status === 'rejected'){
onRejected(self.err)
}
})
}
Promise.resolve(res) 、 同步代码的执行情况下 上述逻辑成立
参数onFulfilled,onRejected 分别有自己的参数, 分别是resolve的参数跟reject的参数
res 跟err 来源如下
function Promise(executor){
let self = this
this.status = 'pending' // Promise 的状态值
this.res = undefined // 存成功之后的值
this.err = undefined // 存失败之后的值
executor(resolve,reject)
// 省略代码
}
executor 有2个参数 分别为resolve,reject
当调用
new Promise((resolve,reject)=>{
setTimeout(()=>{
if(true){
resolve('res')
}else{
reject('err')
}
},1000)
})
executor 会执行 并且把成功的值或者失败的值抛出来,resolve跟reject也是2个函数 定义在Promise内部
function Promise(executor){
// ...代码省略
function resolve(res){
self.res = res
}
function reject(err){
self.err = err
}
executor(resolve,reject)
}
resolve 跟reject 还需要改变 Promise的状态值 并且一旦发生改变之后不能再次改变
function Promise(executor){
// 代码省略
function resolve(res){
if(self.status === 'pending'){
self.status = 'resolved'
self.res = res
}
}
function reject(err){
if(self.status === 'pending'){
self.status = 'rejected'
self.err = err
}
}
executor(resolve,reject)
}
我们在executor中操作的往往是异步代码, 这个之后直接then, status的状态值并未发生改变, 所以不会执行onFulfilled跟onRejected,
这个时候我们需要订阅
function Promise(executor){
// 代码省略
this.onFulfilledCallback = [] // 存成功之后的回调
this.onrejectedCallback = [] // 存失败之后的回调
function resolve(res){
if(self.status === 'pending'){
self.status = 'resolved'
self.res = res
}
}
function reject(err){
if(self.status === 'pending'){
self.status = 'rejected'
self.err = err
}
}
executor(resolve,reject)
}
new Promise(executor).then((onFulfilled,onrejected)=>{
var self = this; // 保存当前上下文 **注意: 第二次调用then this是指向new Promise的**
return new Promise(function(resolve,reject){
// ...代码省略
if(self.status === 'pending'){
self.onFulfilledCallback.push(function(){ // 把成功之后需要做的事存起来 有多少个then就有多少个函数
onFulfilled(self.res) // 注意 这里的self.res 会随着then的调用发生改变 因为每次then都new 了一个Promise
})
self.onrejectedCallback.push(function(){ // 把失败之后的事存起来 有多少个then就有多少个函数
onFulfilled(self.err)
})
}
})
})
当resolve的时候 或者reject的时候
一一拿出来执行
function resolve(res){
// 省略代码
self.res = res
onFulfilledCallback.forEach(fn=>{
fn()
})
}
实现链式调用我们需要对then函数执行的返回值做一个操作!!!
需求:
then的参数onFulfilled函数 需要接收到上一个onfulfilled的执行结果
Promise.prototype.then = function(onFulfilled,onRejected){
return new Promise((resolve,reject)=>{
// ...代码省略
if(self.status === 'resolved'){
let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行Promise.resolve() 同步代码
// 然后把x传递给下一个then
resolve(x)
}
})
}
如果resolve是异步的话
Promise.prototype.then = function(onFulfilled,onRejected){
return new Promise((resolve,reject)=>{
// ...代码省略
if(self.status === 'resolved'){
let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行的是Promise.resolve() 同步代码
// 然后把x传递给下一个then
resolve(x)
}
if(self.status === 'pending'){
self.onFulfilledCallback.push(function(){
let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 相当于 fn(){let x = onFulfilled}
resolve(x)
})
}
})
}
// 同时为了拿到 fn(){let x = onFulfilled ...} 得值 传递给下一个onFulfilled,onFulfilledCallback需要改写 onRejectedCallback同理
onFulfilledCallback.forEach(fn=>{
return fn()
})
onRejectedCallback.forEach(fn=>{
return fn()
})
onFullfillled 的返回值可能是个promise 也可能是个普通值
考虑如下情况:
1. 返回值是个promise
Promsie.resolve(11).then(res=>{
return new Promise(executor)
})
2. 返回值是个普通值
Promsie.resolve(11).then(res=>{
return 1
})
最关键的来了
我们需要对onFullfillled 的返回值进行判断
修改then函数
// ...代码省略
if(self.status === 'resolved'){
let x = onFulfilled(self.res) // 拿到onFulfilled的执行结果 注意:这里执行的是Promise.resolve() 同步代码
// 然后把x传递给下一个then
promiseResolve(x,resolve,reject)
}
function promiseResolve(x,resolve,reject){
if((typeof x != null && typeof x == 'object') || typeof x == 'function'){ // 确定是个引用类型
if (x instanceof Promise){ // 确定是个Promise 实例
let then = x.then
then.call(x,res=>{ // 保证x调用res=>{}, res=>{}是then的onFulfilled方法 一直判断直到onFulfilled 返回的是个普通值 然后resolve出去
promiseResolve(res,resolve,reject)
},err=>{
reject(err)
})
}
}else{
resolve(x)
}
}
考虑这样极端问题:
let p = new Promise(resolve=>{
resolve(3333)
})
let p2 = p.then(resolve=>{
return p2
})
这样会出现什么问题呢, onFulfilled的返回结果如果是一个promise 上面的递归调用已经说明了 我们要不断的去递归最终的onFulfilled结果 然后再改变p2的status 这样变成了p2去等待p2的执行结果 函数死掉了
所以onFulfilled的返回结果需要跟then的返回结果去比较 修改函数
function promiseResolve(x,resolve,reject,promise){
if(x === promise ){
return new Error('引用错误!')
}
if((typeof x != null && typeof x == 'object') || typeof x == 'function'){ // 确定是个引用类型
if (x instanceof Promise){ // 确定是个Promise 实例
let then = x.then
then.call(x,res=>{ // 保证x调用res=>{}, res=>{}是then的onFulfilled方法 一直判断直到onFulfilled 返回的是个普通值 然后resolve出去
promiseResolve(res,resolve,reject)
},err=>{
reject(err)
})
}
}else{
resolve(x)
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
// ...代码省略
let promise2 = new Promise((resolve,reject)=>{
if(self.status === 'pending'){
self.onFulfilledCallback.push(function(){
let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 相当于 fn(){let x = onFulfilled}
promiseResolve(x,resolve,reject,promise2)
})
}
})
return promise2
}
这段代码还是有错误, 由于javascript主线程是单线程的, 所以在then里的promiseResolve是拿不到promise2的 所以我们需要开启异步 使用定时器或者nextTick 这里我们用定时器
Promise.prototype.then = function(onFulfilled,onRejected){
// ...代码省略
let promise2 = new Promise((resolve,reject)=>{
if(self.status === 'pending'){
self.onFulfilledCallback.push(function(){
setTimeout(()=>{
let x = onFulfilled(self.res) // 这里的self.res 是上一个new Promise上的值 此时的onFUlfilled 相当于 fn(){let x = onFulfilled}
promiseResolve(x,resolve,reject,promise2)
},0)
})
}
})
return promise2
}
此时 整个then差不多完成了
then每次创建一个新的promise对象 对于同步的resolve,reject直接调用onFulfilled或者onRejected ,对于异步的resolve,reject使用
订阅发布模式,把每个resolve,reject 暂存起来 等达到条件时候一一执行, 并且拿到返回结果去跟内部的promise比较,并且判断如果是一个promise的话,不断解析onFulfilled 的返回结果 直至resolve出去
Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。
本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.
Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数
这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。
在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,
最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因
想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行
你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve
Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难.本篇大概分为以下步骤:实现简单的同步Promise、增加异步功能、增加链式调用then、增加catch finally方法、增加all race 等方法、实现一个promise的延迟对象defer、最终测试
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!