跳至主要內容

Promise

程序员李某某大约 11 分钟

Promise

基本使用

Promise是一门新的技术 (ES6规范 )

Promise是 异步编程的 新解决方案

Promise是一个构造函数

Promise对象用来封装一个异步操作并可以获取其成功 /失败的结果值

Promise解决了回调地狱

Promise有一个构造函数,有一个参数,这个参数是一个函数,函数两个形参,resolved函数 和 rejected函数 ,用来接收成功或失败的结果,方便后面链式调用,这个函数的函数体就是要执行的异步任务

// 封装
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        const time = Date.now()
        if (time % 2 === 1) {
            resolve('成功' + time)
        } else {
            reject('失败' + time)
        }
    }, 1000)
})

// 调用
p.then(
    value=>{
        console.log(value)
    },
    reason=>{
        console.log(reason)
    }
)

进化一:封装

延时器

// 封装为函数
function doDelay(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const time = Date.now()
            if (time % 2 === 1) {
                resolve('成功' + time)
            } else {
                reject('失败' + time)
            }
        }, time)
    })
}

// 通过函数实例化
const p = doDelay(2000)
p.then(
    value => {
        console.log(value)
    },
    reason => {
        console.log(reason)
    }
)

ajax请求

function get(url) {
    return new Promise((resolve, reject) => {
        const x = new XMLHttpRequest()
        x.open('get', url)
        x.send()
        x.onreadystatechange = () => {
            if (x.readyState !== 4) return

            const { status, response } = x
            if (status >= 200 && status < 300) {
                resolve(JSON.parse(response))
            } else {
                reject(new Error('请求失败:status = ' + status))
            }
        }
    })
}

get('http://www.baidu/com')
    .then(data => {
        console.log(data)
    }, err => {
        console.log(err)
    })

封装fs模块

function readFile(path) {
    return new Promise((resolve, reject) => {
        require('fs').readFile(path, (err, data) => {
            if (err) reject(err)
            resolve(data)
        })
    })
}

readFile('./js/server.js').then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
})

进化二:util包

封装到util模块

const util = require('util')
const fs = require('fs')
const readFile = util.promisify(fs.readFile)

readFile('./js/server.js').then(value=>{
    console.log(value.toString())
},reason=>{
    console.log(reason)
})

进化三:async与await

async是个关键字,作用在函数上,返回Promise对象

  • 若函数返回值为非Promise,返回Promise对象,状态为成功,结果就是返回值
  • 若函数返回值为Promise对象,返回Promise对象,状态和结果由返回的Promise对象决定
  • 若函数抛异常,返回Promise对象,状态为失败,结果就是异常内容

await也是一个关键字,必须定义在async函数内部

  • 若await后跟Promise对象,返回值为成功的值
  • 若await后跟非Promise,返回啥就是啥
  • 失败的情况,需要try-catch捕获
// await 必须在async函数中使用
async function test(){
    const await1 = await {name:'qqq'}
    const await2 = await new Promise((resolve,reject)=>{
        resolve(11)
    })
    try {
        const await3 = await new Promise((resolve,reject)=>{
            reject(11)
        })
        console.log(await3)
    } catch (error) {
        console.log(error)
    }
}

test()

进化到async与await

const fs = require('fs')
const util = require('util')
const readFile = util.promiseify(fs.readFile)

async function main(){
    try{
        const data = await readFile('./1.html')
        const data = await readFile('./2.html')
    }catch(e){
        console.log(e)
    }
}
mian()
function get(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest
        xhr.responseType = 'json'
        xhr.open('get', url)
        xhr.send()
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response)
                } else {
                    reject(xhr.status)
                }
            }
        }
    })
}

const btn = document.querySelector('.test')
btn.addEventListener('click',async function(){
    const data = await get('http://www.baidu.com')
    console.log(data)
})

原理

属性

Promise有两个属性,PromiseState状态、PromiseResult结果

状态pending变为 resolved ---- 待定到解决 --- resolved 和 fulfilled 意思一样

状态pending变为 rejected ---- 待定到拒绝

只有这 2种 , 且一个 promise对象只能改变一次,无论变为成功还是失败 , 都会有一个结果数据,成功的结果数据一般称为 value, 失败的结果数据一般称为 reason

const p = new Promise((resolve, reject) => {
    if (1 === 1) {
        resolve(2)
        reject('xxxxx')
    }
})
// 上述程序的PromiseState为 fulfilled ,PromiseResult为2,说明状态只能改变一次

原型方法

then是Promise的原型对象的方法Promise.prototype.then,两个回调函数,

  • onResolved 监听成功的返回信息 (value)=>{}
  • onRejected 监听失败的返回信息 (reason)=>{}

catch也是Promise原型对象的方法,一个回调函数,等价于 then(undefined, onRejected),用于捕获失败信息

方法

resolve 和 reject 是 Promise 的静态方法

  • Promise.resolve() 中传入的是 非Promise对象,返回一个Promise对象,状态为成功,结果为传入的内容
  • Promise.resolve() 中传入的是 Promise对象,返回的Promise对象状态和结果都由传入的决定
  • Promise.reject() 也是相同道理

Promise 还有两个静态方法 all 和 race

  • 参数是一个Promise对象数组
  • all 在都返回成功的情况下 才能拿到成功的结果,否则在失败的结果中列出失败的结果
  • race 第一个执行完的,即Promise的状态最先改变的那个对象的结果为准
const pAll = Promise.all([p1, p3, p5])
const pRace = Promise.race([p5, p1, p4])

其他问题

当执行了resolve方法,对象的状态就会从pending变为resolved

当执行了reject方法 或 抛出了异常,对象的状态就会从pending变为reject

正常情况下是先指定回调再改变状态 , 但也可以先改状态再指定回调

  • 直接调用resolve或reject或抛异常或延迟调用then,会在状态改变后再指定回调
  • 如果先指定回调,当状态发生改变时,回调函数才调用,拿到数据
  • 如果先改变状态,当指定回调时,回调函数就会调用,拿到数据
let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
    }, 1000);
});

p.then(value => {
    console.log(value);
},reason=>{
    
})

// 延迟调用then
setTimeout(() => {
    p.then(value => {
    	console.log(value);
	},reason=>{})
}, 2000);

promise.then()返回的新 promise,状态由then回调函数执行的结果决定

  • 如果抛出异常 , 新 promise变为 rejected, 结果为抛出的异常
  • 如果返回的是非 promise的任意值 , 新 promise变为 resolved, 结果为返回的值
  • 如果返回的是另一个新 promise, 此 promise的结果就会成为新 promise的结果

链式编程是由于then调用后返回新的Promise对象

  • 成功或失败的结果,在下层then中得到处理
  • 任何一层出现的异常,都会穿透到最后,在最后统一捕获

手动中断 --- 可以在回调函数中返回一个pending状态的Promise对象new Promise(()=>{})

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK');
    }, 1000);
});

p.then(value => {
    console.log(111);
    //有且只有一个方式
    return new Promise(() => {});
}).then(value => {
    console.log(222);
}).then(value => {
    console.log(333);
}).catch(reason => {
    console.warn(reason);
});

多个回调都可以拿到结果

const p = new Promise((resolve, reject) => {
    // resolve('OK')
})

///指定回调 - 1
p.then(value => {
    console.log(value)
})

//指定回调 - 2
p.then(value => {
    alert(value)
})

then调用后没有返回,下层再获取到的是 undefined

手写

第一步,提供一个构造函数new Promise(func),一个原型方法then

function Promise(excutor){

}

Promise.prototype.then = function(onResolved,onRejected){
    
}

第二步,观察new Promise((resolve, reject) => resolve("success"))

excutor是一个函数,有两个参数,resolve和reject是两个函数,参数是结果

function Promise(excutor){

    // 两个方法 -- 参数是结果
    function resolve(data){}    
    function reject(data){ }

    // 执行
    excutor(resolve,reject)
}

第三步,实现resolve和reject方法,达到执行了状态改变

function Promise(excutor) {
    //添加属性
    this.PromiseState = 'pending'
    this.PromiseResult = null
    const self = this               // 由于箭头函数的原因,resolve和reject没有this

    // 两个方法
    function resolve(data) {
        self.PromiseState = 'fulfilled'
        self.PromiseResult = data
    }

    function reject(data) {
        self.PromiseState = 'rejected'
        self.PromiseResult = data
    }

    // 执行
    excutor(resolve, reject)
}

第四步,throw异常改变状态 --- 抛异常就要捕获

function Promise(executor){

    this.PromiseState = 'pending'
    this.PromiseResult = null
    //保存实例对象的 this 的值
    const self = this

    function resolve(data){
        self.PromiseState = 'fulfilled'
        self.PromiseResult = data
    }

    function reject(data){
        self.PromiseState = 'rejected'
        self.PromiseResult = data
    }
    try{
        //同步调用『执行器函数』
        executor(resolve, reject)
    }catch(e){
        //修改 promise 对象状态为『失败』
        reject(e)
    }
}

第五步,状态只能改一次

function resolve(data){
    if(self.PromiseState !== 'pending') return;
    self.PromiseState = 'fulfilled'
    self.PromiseResult = data
}

第六步,then执行回调

Promise.prototype.then = function(onResolved, onRejected){
    //调用回调函数  PromiseState
    if(this.PromiseState === 'fulfilled'){
        onResolved(this.PromiseResult)
    }
    if(this.PromiseState === 'rejected'){
        onRejected(this.PromiseResult)
    }
}

第七步,异步任务then执行回调,构造器中声明callback属性 --- then中处理pendding状态

this.callback = {}
function resolve(data){
    if(self.PromiseState !== 'pending') return
    self.PromiseState = 'fulfilled'
    self.PromiseResult = data;
    //调用成功的回调函数
    if(self.callback.onResolved){
        // 执行回调函数
        self.callback.onResolved(data);
    }
}

function reject(data){
    if(self.PromiseState !== 'pending') return;
    self.PromiseState = 'rejected'
    self.PromiseResult = data
    //执行回调
    if(self.callback.onResolved){
        self.callback.onResolved(data)
    }
}
Promise.prototype.then = function(onResolved, onRejected){
    if(this.PromiseState === 'fulfilled'){
        onResolved(this.PromiseResult)
    }
    if(this.PromiseState === 'rejected'){
        onRejected(this.PromiseResult)
    }
    //判断 pending 状态
    if(this.PromiseState === 'pending'){
        //保存回调函数
        this.callback = {
            onResolved: onResolved,
            onRejected: onRejected
        }
    }
}

第八步,指定多个回调的情形 --- 将callback属性改为数组

this.callbacks = []
function resolve(data){
    if(self.PromiseState !== 'pending') return
    self.PromiseState = 'fulfilled'
    self.PromiseResult = data
    // 执行回调函数
    self.callbacks.forEach(item => {
        item.onResolved(data)
    })
}
Promise.prototype.then = function(onResolved, onRejected){
    if(this.PromiseState === 'fulfilled'){
        onResolved(this.PromiseResult)
    }
    if(this.PromiseState === 'rejected'){
        onRejected(this.PromiseResult)
    }
    //判断 pending 状态
    if(this.PromiseState === 'pending'){
        //追加到callback
        this.callbacks.push({
            onResolved: onResolved,
            onRejected: onRejected
        })
    }
}

第九步,then方法返回值

Promise.prototype.then = function(onResolved, onRejected){
    return new Promise((resolve, reject) => {
        //调用回调函数  PromiseState
        if(this.PromiseState === 'fulfilled'){
            try{
                //获取回调函数的执行结果
                let result = onResolved(this.PromiseResult);
                //判断
                if(result instanceof Promise){
                    //如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //结果的对象状态为『成功』
                    resolve(result);
                }
            }catch(e){
                reject(e);
            }
        }
        if(this.PromiseState === 'rejected'){
            onRejected(this.PromiseResult);
        }
        //判断 pending 状态
        if(this.PromiseState === 'pending'){
            //保存回调函数
            this.callbacks.push({
                onResolved: onResolved,
                onRejected: onRejected
            });
        }
    })
}

第十步,异步then返回值 --- then中处理pendding状态

Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    return new Promise((resolve, reject) => {
        //调用回调函数  PromiseState
        if(this.PromiseState === 'fulfilled'){
            try{
                //获取回调函数的执行结果
                let result = onResolved(this.PromiseResult);
                //判断
                if(result instanceof Promise){
                    //如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //结果的对象状态为『成功』
                    resolve(result);
                }
            }catch(e){
                reject(e);
            }
        }
        if(this.PromiseState === 'rejected'){
            onRejected(this.PromiseResult);
        }
        //判断 pending 状态
        if(this.PromiseState === 'pending'){
            //保存回调函数
            this.callbacks.push({
                onResolved: function(){
                    try{
                        //执行成功回调函数
                        let result = onResolved(self.PromiseResult);
                        //判断
                        if(result instanceof Promise){
                            result.then(v => {
                                resolve(v);
                            }, r=>{
                                reject(r);
                            })
                        }else{
                            resolve(result);
                        }
                    }catch(e){
                        reject(e);
                    }
                },
                onRejected: function(){
                    try{
                        //执行成功回调函数
                        let result = onRejected(self.PromiseResult);
                        //判断
                        if(result instanceof Promise){
                            result.then(v => {
                                resolve(v);
                            }, r=>{
                                reject(r);
                            })
                        }else{
                            resolve(result);
                        }
                    }catch(e){
                        reject(e);
                    }
                }
            });
        }
    })
}

优化then --- 封装

Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    return new Promise((resolve, reject) => {
        //封装函数
        function callback(type){
            try{
                //获取回调函数的执行结果
                let result = type(self.PromiseResult);
                //判断
                if(result instanceof Promise){
                    //如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //结果的对象状态为『成功』
                    resolve(result);
                }
            }catch(e){
                reject(e);
            }
        }
        //调用回调函数  PromiseState
        if(this.PromiseState === 'fulfilled'){
            callback(onResolved);
        }
        if(this.PromiseState === 'rejected'){
            callback(onRejected);
        }
        //判断 pending 状态
        if(this.PromiseState === 'pending'){
            //保存回调函数
            this.callbacks.push({
                onResolved: function(){
                    callback(onResolved);
                },
                onRejected: function(){
                    callback(onRejected);
                }
            });
        }
    })
}

第11步,catch穿透

Promise.prototype.catch = function(onRejected){
    return this.then(undefined, onRejected);
}

Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    //判断回调函数参数
    if(typeof onRejected !== 'function'){
        onRejected = reason => {
            throw reason;
        }
    }
    if(typeof onResolved !== 'function'){
        onResolved = value => value;
        //value => { return value};
    }
	...
}

第12步,实现 resolve 和 reject

Promise.resolve = function(value){
    //返回promise对象
    return new Promise((resolve, reject) => {
        if(value instanceof Promise){
            value.then(v=>{
                resolve(v);
            }, r=>{
                reject(r);
            })
        }else{
            //状态设置为成功
            resolve(value);
        }
    });
}

Promise.reject = function(reason){
    return new Promise((resolve, reject)=>{
        reject(reason);
    });
}

第13步,实现all 和 race

Promise.all = function(promises){
    //返回结果为promise对象
    return new Promise((resolve, reject) => {
        //声明变量
        let count = 0;
        let arr = [];
        //遍历
        for(let i=0;i<promises.length;i++){
            //
            promises[i].then(v => {
                //得知对象的状态是成功
                //每个promise对象 都成功
                count++;
                //将当前promise对象成功的结果 存入到数组中
                arr[i] = v;
                //判断
                if(count === promises.length){
                    //修改状态
                    resolve(arr);
                }
            }, r => {
                reject(r);
            });
        }
    });
}

Promise.race = function(promises){
    return new Promise((resolve, reject) => {
        for(let i=0;i<promises.length;i++){
            promises[i].then(v => {
                //修改返回对象的状态为 『成功』
                resolve(v);
            },r=>{
                //修改返回对象的状态为 『失败』
                reject(r);
            })
        }
    });
}

第14步,then中的回调函数异步执行

//声明构造函数
function Promise(executor){
    //添加属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //声明属性
    this.callbacks = [];
    //保存实例对象的 this 的值
    const self = this;// self _this that
    //resolve 函数
    function resolve(data){
        //判断状态
        if(self.PromiseState !== 'pending') return;
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = 'fulfilled';// resolved
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用成功的回调函数
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onResolved(data);
            });
        });
    }
    //reject 函数
    function reject(data){
        //判断状态
        if(self.PromiseState !== 'pending') return;
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = 'rejected';// 
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //执行失败的回调
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onRejected(data);
            });
        });
    }
    try{
        //同步调用『执行器函数』
        executor(resolve, reject);
    }catch(e){
        //修改 promise 对象状态为『失败』
        reject(e);
    }
}

//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    //判断回调函数参数
    if(typeof onRejected !== 'function'){
        onRejected = reason => {
            throw reason;
        }
    }
    if(typeof onResolved !== 'function'){
        onResolved = value => value;
        //value => { return value};
    }
    return new Promise((resolve, reject) => {
        //封装函数
        function callback(type){
            try{
                //获取回调函数的执行结果
                let result = type(self.PromiseResult);
                //判断
                if(result instanceof Promise){
                    //如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //结果的对象状态为『成功』
                    resolve(result);
                }
            }catch(e){
                reject(e);
            }
        }
        //调用回调函数  PromiseState
        if(this.PromiseState === 'fulfilled'){
            setTimeout(() => {
                callback(onResolved);
            });
        }
        if(this.PromiseState === 'rejected'){
            setTimeout(() => {
                callback(onRejected);
            });
        }
        //判断 pending 状态
        if(this.PromiseState === 'pending'){
            //保存回调函数
            this.callbacks.push({
                onResolved: function(){
                    callback(onResolved);
                },
                onRejected: function(){
                    callback(onRejected);
                }
            });
        }
    })
}

//添加 catch 方法
Promise.prototype.catch = function(onRejected){
    return this.then(undefined, onRejected);
}

//添加 resolve 方法
Promise.resolve = function(value){
    //返回promise对象
    return new Promise((resolve, reject) => {
        if(value instanceof Promise){
            value.then(v=>{
                resolve(v);
            }, r=>{
                reject(r);
            })
        }else{
            //状态设置为成功
            resolve(value);
        }
    });
}

//添加 reject 方法
Promise.reject = function(reason){
    return new Promise((resolve, reject)=>{
        reject(reason);
    });
}

//添加 all 方法
Promise.all = function(promises){
    //返回结果为promise对象
    return new Promise((resolve, reject) => {
        //声明变量
        let count = 0;
        let arr = [];
        //遍历
        for(let i=0;i<promises.length;i++){
            //
            promises[i].then(v => {
                //得知对象的状态是成功
                //每个promise对象 都成功
                count++;
                //将当前promise对象成功的结果 存入到数组中
                arr[i] = v;
                //判断
                if(count === promises.length){
                    //修改状态
                    resolve(arr);
                }
            }, r => {
                reject(r);
            });
        }
    });
}

//添加 race 方法
Promise.race = function(promises){
    return new Promise((resolve, reject) => {
        for(let i=0;i<promises.length;i++){
            promises[i].then(v => {
                //修改返回对象的状态为 『成功』
                resolve(v);
            },r=>{
                //修改返回对象的状态为 『失败』
                reject(r);
            })
        }
    });
}
上次编辑于:
贡献者: ext.liyuanhao3