当前位置: 首页 > news >正文

Promise(基础)

Promise是什么

1.promise是一门新的技术(ES6规范)
2.Promise是JS中一编程的解决方案(旧的解决方案是单纯的使用回调函数)
3.promise一个构造函数,promise队形用来封装一个一步操作并可以获取其成功/失败的结果值。
注常见的异步操作:文件操作、数据库操作、AJAX、定时器

那么promise有哪些优势呢?
1.支持链式调用
2.解决地狱回调的问题(地狱回调就是,在回调中嵌套回调),不易于代码的维护。

promise hello world

// 普通的异步任务
<body>
    <button id="btn">点击抽奖</button>
</body>
<script>
    const but = document.getElementById("btb");
    btn.addEventListener('click', function () {
        setTimeout(() => {
            const n = Math.random(1, 100);
            if (n <= 0.3) alert("中奖了");
            else alert("没有中奖");
        }, 1000)
    })
</script>

promise写法

// 用promise包裹异步操作
<body>
    <button id="btn">点击抽奖</button>
</body>
<script>
    const but = document.getElementById("btb");
    btn.addEventListener('click', function () {
        // 参数为函数类型
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                const n = Math.random(1, 100);
                if (n <= 0.3) resolve();
                else reject();
            }, 1000)
        });
        // 指定回调,成功执行resolve函数,执行失败执行reject函数
        p.then(() => {
            alert("中奖了");
        }, () => {
            alert("没有中奖")
        })
    })
</script>

如果要传递参数

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        const n = Math.random(1, 100);
        if (n <= 0.3) resolve(n);
        else reject(n);
    }, 1000)
});
// 指定回调时接受参数
p.then((val) => {
    alert("中奖了" + val);
}, (val) => {
    alert("没有中奖" + val)
})

promise基础实践(熟悉写法)

  • 文件操作(需要node环境)
// 普通代码
const fs = require('fs');
fs.readFile('./data.txt', (err, data) => {
    if (err) console.log(err);
    else console.log(data);
})

promise封装

// promise封装
const fs = require('fs');
const p = new Promise((resolve, reject) => {
    fs.readFile('./data.txt', (err, data) => {
        if (err) reject(err);
        else resolve(data);
    })
})
p.then((data) => {
    console.log("读取文件成功!!!")
    console.log(data)
}, (err) => {
    console.log("读取文件成功!!!")
    console.log(err)
})
  • ajax封装
// 原始写法
var XMLHttpRequest = require('xhr2');
function send() {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://127.0.0.1:8888");
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status <= 300) {
                console.log("成功!!!")
                console.log(xhr.response)
            } else {
                console.log("失败!!!")
                console.log(xhr.status)
            }
        }
    }
}
send()
// promise写法
const p = new Promise((resolve, reject) =>{
    const xhr = new XMLHttpRequest();
    xhr.open("GET", "http://127.0.0.1:8888");
    xhr.send();
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status <= 300) {
                console.log("成功!!!")
                resolve(xhr.response);
            } else {
                console.log("失败!!!")
                reject(xhr.status);
            }
        }
    }
})
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
})

Promise知识点

  • util.promisify promise对象转换
const fs = require("fs")
const util = require("util");
// 将回调函数转换为promise对象
const  preadFile = util.promisify(fs.readFile)
preadFile("./data.txt").then((data) => {
    console.log(data.toString())
});
  • promise的状态改变
    promise实例的[promiseState]
  • pendging 未决定的
  • resolved/fullfilled 成功
  • rejected 失败
    promise的状态改变只有两种情况:
    pending 变为resolved
    pending 变为rejected
  • promise 对象的值
    实实例属性[promiseResult] 保存着对象[成功/失败]的结果
    只有resolve和reject函数可以修改这个结果值

  • promise的工作流程
    在这里插入图片描述

  • Promise API
    1)Promise构造函数 Promise(excutor) {}
    executor函数 : 执行器(resolve, reject) => {}
    resolve函数 : resolve
    reject函数 : reject

2)Then方法 (onResolved, onRejected) => {}
onRedolved函数 : 成功的回调函数
onRejected函数 : 失败的回调函数

3)Promise.prototype.catch 方法 (onrejected)=> {}
onRejected 函数:失败的回到
注:这个方法只能指定失败的回调函数

4)Promise.resolve()

// 如果resolve中传入的参数为非promise对象则返回的结果为resolve的结果,成功的结果为参数
// 如果传入的参数为promise对象结果取决于参数的结果
let p = Promise.resolve(521)
console.log(p)

let p = new Promise(new Promise((resolve, reject) => {}));

5)Promise.reject()

// 如果resolve中传入的参数为非promise对象则返回的结果为reject的结果,失败的结果就是参数
// 如果传入的参数为promise对象结果取决于参数的结果
let p = Promise.reject(521)
console.log(p)

let p = new Promise(new Promise((resolve, reject) => {}));

6)Promise.all()
包含n个promise数组,结果返回一个新的promise,只有所以的promise都成功才成功,只要有一个失败就是败。

let p1 = new Promise((resolve, reject) => {
    resolve('ok')
})
let p2 = Promise.resolve("ok");
let p3 = Promise.reject("error");
const res = Promise.all([p1, p2, p3])
console.log(res)

7)Promise.race()
返回一个新的promise对象,第一个完成的promise的状态就是最终的状态。
应用场景:比如提供了多个接口,效率不一样谁先返回用谁的结果。

8)改变promise的状态
初始状态为pending,之后可以调用resolve和reject改变状态,throw爆出错误也可以改变promise的状态。
9)Promise指定多个成功回调会执行吗

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(v => {
    console.log(v)
})
p.then(v => {
    console.log(v + 1)
})
// 验证可知多个回调都会执行,如果Promise一直为pending状态则不会执行

10)改变状态和指定函数回调谁先谁后?
都有可能
如果promise中是同步任务则是先改变状态,然后指定回调。如果是异步任务则可能是先指定回调然后再改变状态
11)then链式调用

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(() =>{
    return new Promise((resolve, reject) => {
        resolve("success")
    })
}).then(v => {
    console.log(v)
}).then(v => {
    // 输出undifined,因为上一个thenPromise的返回结果没有写
    console.log(v)
})

12)异常穿透
通过then链式调用的时候发生错误可以在最终来进行指定回调来处理。

let p = new Promise((resolve, reject) => {
    resolve('ok')
})
p.then(() =>{
    return new Promise((resolve, reject) => {
        reject("err")
    })
}).then(v => {
    console.log(v)
}).then(v => {
    // 输出undifined
    console.log(v)
}).catch((err) => {
    console.log(err)
})

13)终端promise链
需要在then方法中返回一个pending状态的promise才能终端promise链

Promise 自定义封装

此部分需要多写多练

class Promise {
    constructor(executor) {
        this.promiseState = "pending"
        this.promiseResult = null
        // 用于保存异步任务的回调函数
        this.callbacks = []
        // 这里需要注意this问题
        // 可以先存下来self = this 后面用self替代this
        const self = this;
        function resolve(data) {
            // 保证状态只改变一次
            if (self.promiseState !== "pending") return
            self.promiseState = 'resolved'
            self.promiseResult = data
            // 指定多个回调
            // 使得它进入异步队列,用定时器包裹
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onResolved(data);
                })
            })

        }
        function reject(data) {
            if (self.promiseState !== "pending") return
            self.promiseState = 'rejected'
            self.promiseResult = data
            // 指定多个回调
            setTimeout(() => {
                self.callbacks.forEach(item => {
                    item.onRejected(data);
                })
            })

        }
        try {
            executor(resolve, reject);
        } catch (err) {
            // 直接调用reject函数改变状态为rejected
            reject(err)
        }
    }
    then(onResolved, onRejected) {
        const self = this;
        // 异常穿透的逻辑
        if (typeof onRejected !== "function") {
            onRejected = reason => {throw reason};
        }
        if (typeof onResolved !== "function") {
            onResolved = value => value;
        }
        return new Promise((resolve, reject) => {
            function callback(method) {
                try {
                    let result = method(self.promiseResult)
                    // 如果返回的是promise对象,promise的结果取决于这个promise的结果
                    if (result instanceof Promise) {
                        result.then(v => {
                            resolve(v);
                        }, e => {
                            reject(e)
                        })
                    } else {
                        // 如果返回的是值,promise的结果就是这个值
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }

            if (this.promiseState === "resolved") {
                setTimeout(() => {
                    callback(onResolved)
                })

            } else if (this.promiseState === "rejected") {
                setTimeout(() => {
                    callback(onRejected)
                })
            } else {
                // 这里异步任务先指定回调,由于可以指定多个回调所以用数组保存
                this.callbacks.push({
                    onResolved: function () {
                        callback(onResolved)

                    },
                    onRejected: function () {
                        callback(onRejected)
                    }
                });
            }
        })
    }
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    static resolve(value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                        resolve(v)
                    },
                    e => {
                        reject(e)
                    })
            } else {
                resolve(value)
            }
        })
    }
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        })
    }
    static all(promise) {
        return new Promise((resolve, reject) => {
            let count = 0;
            const res = [];
            for (let i = 0; i < promise.length; i++) {
                promise[i].then((v) => {
                    res[i] = v
                    count++;
                }, (r) => {
                    reject(r)
                })
                if (count == promise.length) {
                    resolve(res);
                }
            }
        })
    }

    static race(promise) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promise.length; i++) {
                promise[i].then((v) => {
                    resolve(v)
                }, (r) => {
                    reject(r)
                })
            }
        })
    }
}

参考视频:
Promise教程

相关文章:

  • 最专业的手机网站建设/推广优化方案
  • h5 做的网站 价格/短信营销平台
  • 网站开发项目计划/百度小说搜索风云榜
  • 怎么做 废旧回收网站/长沙网站制作费用
  • 宿迁定制网站建设/长尾关键词什么意思
  • app怎么查网站备案/站长统计app软件下载
  • 冰蝎V4.0流量分析到攻防检测
  • 【vue系列-06】vue的组件化编程
  • 招标采购中,如何编写有效的RFI(信息邀请书)?
  • 【web】微信小程序笔记小结(模板与配置)
  • shell 脚本中 的> /dev/null 2>1
  • python-while循环
  • Dopamine-PEG-N3,多巴胺聚乙二醇叠氮 科研试剂用于点击化学
  • 35岁高龄程序员的 4 条出路,提早布局,避免出局!
  • ROS | Realsense中的IMU解算orientation
  • Mysql入门技能树-数据查询-练习篇
  • 全流量分析为企业提升SAP用户体验
  • 【JavaEE】多线程之线程安全(synchronized篇),死锁问题