promise--又双叒叕学

了解promise之前需要先了解什么是异步编程

异步编程:
我们知道Javascript语言的执行环境是"单线程"。也就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。但是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。

因此出现了两种模式:同步和异步

异步任务就是不具有”堵塞“效应

Promise 是用来管理异步编程的,它本身不是异步的

Promise就是异步编程的解决方案之一


Promise本身是一个对象,是一个构造函数,它需要传入一个参数,并且这个参数必须是函数;传入的这个函数本身包含两个参数resolvereject,这两个参数也分别是函数;

new Promise((resolve,reject) => {
 // 箭头函数
 // 异步函数(定时器,事件和 ajax)
 setTimeout( ()=> { });
});

Promise的三种状态

  • 待定(pending)
  • 兑现(fulfilled,有时也称为解决,resolve)
  • 拒绝(rejected)

有两种过度:pending -> fulfilled或者是pending -> rejected
 

resolve.then、reject.catch

  • then方法接受一个参数-resolve返回的数据(正常时),(遇到resolve函数会执行then)
  • catch方法接收一个参数-reject返回的信息(抛出异常),(遇到reject函数汇之星catch)
new Promise((resolve,reject) => {
    setTimeout(()=> {
    	//resolve('success')
     	reject('Error Data')
    },1000)
}).then((data)=>{
	console.log(data);
}).catch((data)=> {
	console.log(data);
})

错误处理

Promise 对象的错误具有“冒泡”性质,会一直向后传递

补充:

1.使用reject

reject('promise使用reject抛出异常')  

2.使用new Error()

let promise = new Promise((reslove, reject) => {
    throw new Error('promise使用Error抛出异常')
})
promise().then(res => {
  console.log(res)
})
.catch(err => {
  console.log(err.message)     //'promise使用Error抛出异常'
})

3.reject一个new Error()

 

    let promise = new Promise((resolve, reject) => {
    
        setTimeout(() => {
            reject(new Error('promise抛出异常'));
        }, 1000);
    })

    promise.then(res => {
        console.log(res);
    })
    .catch(err => {
        console.log(err.message);  //'promise抛出异常'
    })

Promise的链式编程思想

  • 每次你对Promise调用then,它都会创建并返回一个新的Promise,我们可以将其链接起来;
  • 不管从then调用的完成回调(第一个参数)返回的值是什么,它都会被自动设置为被链接Promise(第一点中的)的完成。
let p1=new Promise((resolve,reject)=>{
    resolve('这是p1--resolve') // 决定了下个then中成功方法会被执行
})
// 连接p1
let p2=p1.then(result=>{
    console.log('成功1 '+result)
    return Promise.reject('这是p2--reject') 
// 返回一个新的Promise实例,决定了当前实例是失败的,所以决定下一个then中失败方法会被执行
},reason=>{
    console.log('失败1 '+reason)
    return 200
})
// 连接p2 
let p3=p2.then(result=>{
    console.log('成功2 '+result)
},reason=>{
    console.log('失败2 '+reason)
})
// 成功1 这是p1--resolve
// 失败2 这是p2--reject

new Promise出来的实例,成功或者失败(或者异常),执行的是resolve或reject

new Promise(resolve=>{
    resolve(p) // 报错
// 这个executor函数执行发生异常错误,决定下个then失败方法会被执行
}).then(result=>{
    console.log(`成功:${result}`)
    return result*10
},reason=>{
    console.log(`失败:${reason}`)
// 执行这句时候,没有发生异常或者返回一个失败的Promise实例,所以下个then成功方法会被执行
// 这里没有return,最后会返回 undefined
}).then(result=>{
    console.log(`成功:${result}`)
},reason=>{
    console.log(`失败:${reason}`)
})



VM1580:8 失败:ReferenceError: p is not defined
VM1580:12 成功:undefined
Promise {<fulfilled>: undefined}

Promise.all

let p = Promise.all([p1,p2,p3]);
p.then()
// (全部成功)
// 1.只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
// 2.只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race

let p = Promise.race([p1,p2,p3]);
// (只要有一个成功)只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

Promise.allSettled

//Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。

Promise.any

有一个变成fulfilled状态,包装实例就会变成fulfilled状态;

Promise.resolve

Promise.resolve(param):将对象转为 Promise 对象

Promise.reject

返回一个promise实例,且该实例的状态为rejected。

手写Promise

1)promise是通过构造函数创建的,并且会立即执行里面的构造函数

2)state表示promise的三种状态,三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected),最初为pending;当状态改变后,就不能再次更改状态,且终值也不可改变

3)使用value存放成功的值,reason存放失败原因

4)then的实现:无论成功还是失败都需要执行then函数,需要做的不过是根据状态判断去执行哪一个函数

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function Promise(executor) {
    var _this = this
    this.state = PENDING; //状态
    this.value = undefined; //成功结果
    this.reason = undefined; //失败原因
    function resolve(value) {
        if(_this.state === PENDING){
            _this.state = FULFILLED
            _this.value = value
        }
    }
    function reject(reason) {
        if(_this.state === PENDING){
            _this.state = REJECTED
            _this.reason = reason
        }
    }
    // 实例化时候立即执行构造函数,并传入resolve和reject
    // 异常处理
    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
    if(this.state === FULFILLED){
        typeof onFulfilled === 'function' && onFulfilled(this.value)
    }
    if(this.state === REJECTED){
        typeof onRejected === 'function' && onRejected(this.reason)
    }
};

module.exports = Promise;

5)then支持异步:参考发布订阅模式

先定义两个数组,分别用来存储成功的回调和失败的回调

function Promise(executor) {
    this.onFulfilled = [];//成功的回调
    this.onRejected = []; //失败的回调
}

如果当前还是PENDING状态,就把回调函数寄存到一个数组中,当状态发生改变时(resolve或者reject时),去数组中取出回调函数并执行

// then里面的state为pending时
if(this.state === PENDING){
        typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
        typeof onRejected === 'function' && this.onRejected.push(onRejected)
    }

// 状态改变时
function resolve(value) {
    if(_this.state === PENDING){
        _this.state = FULFILLED
        _this.value = value
        _this.onFulfilled.forEach(fn => fn(value))
    }
}
function reject(reason) {
    if(_this.state === PENDING){
        _this.state = REJECTED
        _this.reason = reason
        _this.onRejected.forEach(fn => fn(reason))
    }
}

综上所说,小结一下:

在我们new Promise的时候,executor就同步的执行了,根据executor里有无异步操作分一下两种情况

有异步操作:

  • executor函数执行完(实例化完成)(此时内部还有个异步函数 如setTimout是异步的,需要等待几毫秒后执行)
  • 拿到实例对象后,代码接着执行.then,此时很明显状态是pending(因为只执行了executor,参数是异步函数,此时未执行就 不会改变状态),我们会把用户在then里传的回调函数存起来
  • 异步函数执行完成后,会遍历onFulfilled,并执行每一项(也就是then里面传过来的回调函数)
  •  不管如何异步,在成功的地方调resolve,在失败的地方调reject,这是规矩,使用Promise必须遵守的规矩。

无异步操作:

  • 执行executor直接就会调resolve,then的会后,任务已经完成,当即执行用户传的回调函数就行了

 

6)then链式调用


Promise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
    var promise2 = new Promise((resolve, reject)=>{
    if(_this.state === FULFILLED){
        let x = onFulfilled(_this.value)
        promiseDeal(promise2, x, resolve, reject)
    } else if(_this.state === REJECTED){
        let x = onRejected(_this.reason)
        promiseDeal(promise2, x ,resolve, reject)
    } else if(_this.state === PENDING){
        _this.onFulfilled.push(()=>{
            let x = onFulfilled(_this.value)
            promiseDeal(promise2, x, resolve, reject)
        })
        _this.onRejected.push(()=>{
            let x = onRejected(_this.reason)
            promiseDeal(promise2, x ,resolve, reject)
        })
    }
    })
    return promise2;
};

 
//  处理 onFulfilled或者onRejected 返回值x和新的promise 的函数
function promiseDeal(promise2, x, resolve, reject){
    if(promise2 === x){
        reject(new TypeError('Chaining cycle'))
    }
    if(x && typeof x === 'object' || typeof x === 'function'){
        let used;
        try {
            let then = x.then
            if(typeof then === 'function'){
                then.call(x, (y)=>{
                    if (used) return;
                    used = true
                    promiseDeal(promise2, y, resolve, reject)
                }, (r) =>{
                    if (used) return;
                    used = true
                    reject(r)
                })
            } else {
                if (used) return;
                used = true
                resolve(x)
            }
        } catch(e){
            if (used) return;
            used = true
            reject(e)
        }
    } else {
        resolve(x)
    }
}

注明:手写promise部分 转载于知乎账号 谢小飞 ,感谢感谢~ https://zhuanlan.zhihu.com/p/144058361

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值