promise基础知识与自定义

1 介绍

promise是一种异步编程方案,es6的一个
异步任务主要体现在ajax,数据库,计时器,fs文件操作
也是一种解决回调地狱的方案,回调地狱也就是函数套娃,解决回调地狱的还有一种es6里的生成器函数yield
在这里回顾一下

function getUsers(){
  setTimeout(() =>{
    let data = "用户数据";
    iterator.next(data);
  }, 1000)
}
function getOrders(){
  setTimeout(() =>{
    let data = "订单数据";
    iterator.next(data);
  }, 1000)
}
function getGoods(){
  setTimeout(() =>{
    let data = "商品数据";
    iterator.next(data);
  }, 1000)
}
function * gen(){
  let users = yield getUsers();
  console.log(users);
  let orders = yield getOrders();
  console.log(orders);
  let goods = yield getGoods();
  console.log(goods);
}
let iterator = gen();//这里将gen实例化,好像是必须实例化,才能在第一个函数中使用next
iterator.next();

2 初体验

promise reject value reson这些名字都是根据习惯来的,不一定要是这个
promise是个构造函数,resolve reject是两个函数
then 用来定义函数内容

let a = 2
let promise = new Promise((resolve, reject)=>{
    if(a > 30){
        resolve(a);
    }
    else{
        reject(a);
    }
}
)
promise.then((value)=>{
    console.log("resolve");
}, (reson)=>{
    console.log("reject");
})

3 用promise来写fs

const fs = require("fs");
const promise = new Promise((resolve, reject)=>{
    fs.writeFile("./content.txt", "我是一个大聪明", "utf-8", (error, data)=>{
        if(error){
            reject(error);
        }
        else{
            resolve(data);
        }
    })
})
promise.then(value=>{
    console.log(value);
}, reason=>{
    console.log(reason);
})
let promise2 = new Promise((resolve, reject) => {
    fs.readFile("./content.txt", "utf-8", (error, data)=>{
        if(error){
            resolve(error);
        }
        else{
            reject(data);
        }
    })
})
promise2.then(value=>{
    console.log(value);
}, reason=>{
    console.log(reason);
})

3.1 封装

//封装函数 参数为路径,返回值为promise对象
function mineReadFile(path){
    return new Promise((resolve, reject) => {
        require("fs").readFile(path, "utf-8", (error, data) => {
            if(error){
                reject(error);
            }
            else{
                resolve(data);
            }
        })
    })
}
//调用
mineReadFile("./content.txt").then(value=>{
    console.log(value);
}, reason=>{
    console.log(reason);
})

这个封装就是将回调函数风格转化成promise风格的函数,而util里的promisify本身就能够实现这个功能
不同的是这个没有指定编码方式,所以传进来的内容需要用到toString()转化成字符串形式

mineReadFile = require("util").promisify(require("fs").readFile);

mineReadFile("./content.txt").then(value=>{
    console.log(value.toString());
}, reason=>{
    console.log(reason);
})

4 promise写AJAX

<button>点击我获取数据</button>
let btn = document.querySelector("button");
btn.addEventListener("click", ()=>{
     const xhr = new XMLHttpRequest();
     xhr.open("GET", "http://127.0.0.1:8000/temp");
     xhr.send();
     xhr.responseType = "json";
     xhr.onreadystatechange = function(){
         if(xhr.readyState == 4){
             if(xhr.status >= 200 && xhr.status < 300){
                 console.log(xhr.response.name);
             }
             else{
                 console.log(xhr.status);
             }
         }
     }
 })

4.1 原生

服务端 node.js

const express = require("express");
const app = express();
app.get("/temp", (request, response) => {
    response.setHeader("Access-Control-Allow-Origin", "*");
    let data = {
        name : "iceylia",
        age: 80
    }
    data = JSON.stringify(data);
    response.send(data);
})
app.listen(8000, ()=>{
    console.log("8000端口已经启用");
})

4.2 promise

let btn = document.querySelector("button");
btn.addEventListener("click", ()=>{
    const promise = new Promise((resolve, reject)=>{
        const xhr = new XMLHttpRequest();
        xhr.open("GET", "http://127.0.0.1:8000/temp");
        xhr.send();
        xhr.responseType = "json";
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                if(xhr.status >= 200 && xhr.status < 300){
                    resolve(xhr.response);
                }
                else{
                    reject(xhr.status);
                }
            }
        }
    })
    promise.then(value=>{
        console.log(value.name);
    }, reason=>{
        console.log(reason);
    });
})

4.3 封装

function sendAJAX(url){
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.send();
        xhr.responseType = "json"
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(this.status >= 200 && this.status < 300){
                    resolve(this.response);
                }
                else{
                    reject(thsi.status);
                }
            }
        }
    })
}
sendAJAX("http://127.0.0.1:8000/temp").then(value=>{
    console.log(value.name);
}, reason => {
    console.log(reason);
})

5 promise实例化属性

下面的属性都是内置的,只读的,无法通过js直接获取
Promise本身就是一个构造函数,也就是在实例化函数对象的时候需要传参,这个参数就是一个函数对象resolve和reject的函数,这个函数被称为执行器(executor)函数,会同步进行,不会到异步队列里面去,也就是直接执行
promise.then()是一个两个参数的实例化方法,就是定义resolve和reject
promise.catch()是用then对失败时的一个单独的封装,用法和then差不多,promise.catch(reason=>{console.log(reason});

5.1 PromiseState

pending是初始化的,未被定义的
resolved 就是成功,成功的数据一般就是value
rejected就是失败,reason
promisestate只能变化一次,就是从pending变为resolved或者是rejected

5.2 PromiseResult

异步任务执行的结果,就是无论成功还是失败,value和reason都保存在这个属性里面

6 promsie的流程

流程图

7 Promise函数对象

7.1 Promise.resolve()

这个函数的返回值是一个promise对象,如何里面的参数不是promise对象,那么返回的就是一个成功的promise对象,PromiseState为resolved,如果是一个promise对象,那么这个对象是一个成功的,返回的就是一个成功的。否则就是一个失败的对象,而PromiseResult的值就是这个函数的参数
比如

let p1 = Promise.resolve("fa");
console.log(p1);
let p2 = Promise.resolve(new Promise((resolve, reject) => {
    reject("errror");
}));
p2.catch(reason => {
    console.log(reason);
});

结果

7.2 Promise.reject()

这个函数就是无论如何结果都是一个失败的promise对象,到现在我还不明白这个函数的意义

7.3 Promise.all()

参数是多个promise对象,只有全部成功才会返回一个成功的promise对象

let p1 = Promise.resolve("faaf");
let p2 = Promise.resolve("success");
let p3 = Promise.resolve("faf");
let p4 = Promise.all([p1, p2, p3]);
console.log(p4);

描述图

7.4 Promise.race()

这个函数就有意思了,参数也是promise数组,结果就是最先完成的promise对象的结果

8 Promise关键问题

如何修改promise对象的状态?调用resolve,reject或者使用throw
对一个promise对象使用多个then,都会执行吗? 会
是先定义then还是先执行resolve和reject改变状态? 当Promise构造函数是一个同步任务的时候,就是先改变状态,异步是先指定then
promise对象的结果是什么?有then执行的回调函数的返回值决定的,then返回的是一个promise对象,而如果执行的是value,然后value那个函数最后是throw,那么就是rejected的promise对象,如果最后是return new Promise()这样的return,那么结果就和return差不多,return 1就是一个resolved的promise对象
promise如何串联多个异步任务,就是promise.then(value=>{return new Promise()}).then();这就是then的链式调用
什么是异常穿透? 在使用then的链式调用的时候,就可以在最后面加上一个catch()比如promise.then().then().catch(reason=>{});这样当你每一次的失败函数是一样的时候,就不需要每个then都使用两个回调函数,一个最后面的catch即可
如何中断promise链?返回一个pending的promise对象,这样后续的then都不会执行了,比如promise.then(value=>{return new Promise()}).then();

9 自定义promise

9.1 初始化结构,能通过resolve和reject改变result和state

resolve data
throw data
reject data
new Promise executor
执行executor
执行then
executor内部函数
resolve
reject
onResolved data
onRejected data
resolve内部函数
promisestate=resolve
reject内部函数
promisestate=reject
promiseresult=data
function Promise(executor){
    const self = this;
    this.PromiseState = "pending";
    this.PromiseResult = "";
    function resolve(data){
        if(self.PromiseState !== pending) return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
    }
    function reject(data){
        if(self.PromiseState !== pending) return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
    }
    executor(resolve, reject);
}
引入
```html
<script src="promise.js"></script>
<script>
    let p = new Promise();
    p.then();
</script>

直接覆盖原本的promise对象
excutor是执行器函数, prototype是原型的意思,也就是实例化的函数对象。

9.2 executor中的throw

如果在executor里写了throw,要抛出错误,就需要写try catch

let p = new Promise ((resolve, reject))=>{
	throw "error";
})
try{
    executor(resolve, reject);
}catch(err){
    reject(err);
}

9.3 then根据state用回调

state=fulfilled
state=rejected
then onresolved,onrejected
onresolved result
onrejected result

onResolved和onRejected都是用户在使用then的时候自定义的两个回调函数
then要做的就是根据executor改变的PromiseState来决定调用哪一个

Promise.prototype.then = function(onResolved, onRejected){
	if(this.PromiseState === "fulfilled"){
	    onResolved(this.PromiseResult);
	}
	if(this.PromiseState === "rejected"){
	    onRejected(this.PromiseResult);
	}
}

9.4 executor是异步函数时的回调

let p = new Promise((resolve, reject) => {
	setTimeout((resolve("ok"))=>{}, 100);
});
executor进入异步队列
then
state=pending
不执行onResolved或者是onRejected
执行executor

可以看到因为executor是异步的,所以没有执行resolve或reject,而是先执行的then,这个时候PromiseState都还没改变,也就不会执行回调

function Promise(executor){
    const self = this;
    this.PromiseState = "pending";
    this.PromiseResult = "";
    this.callbacks = [];
    function resolve(data){
        if(self.PromiseState !== pending) return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
        self.callbacks.forEach(item=>{
            item.onResolved(data);
        });
    }
    function reject(data){
        if(self.PromiseState !== pending) return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
        self.callbacks.forEach(item=>{
            item.onRejected(data);
        });
    }
    try{
        executor(resolve, reject);
    }catch(err){
        reject(err);
    }
}
Promise.prototype.then = function(onResolved, onRejected){
    if(this.PromiseState === "fulfilled"){
        onResolved(this.PromiseResult);
    }
    if(this.PromiseState === "rejected"){
        onRejected(this.PromiseResult);
    }
    if(this.PromiseState === "pending"){
        this.callbacks.push({
            onRejected,
            onResolved
        });
    }
}

这里直接用一个属性callbacks来结束回调,在执行resolve和reject的时候逐一调用,用数组也时为了如果此时有多个then方法

executor进入异步队列
then
state=pending
两个函数暂存callbacks
executor
resolve/reject
callbacks

9.5 then的返回值

如果用户在使用then定义返回值的时候使用了return,那么就接收

function Promise(executor){
    const self = this;
    this.PromiseState = "pending";
    this.PromiseResult = "";
    this.callbacks = [];
    function resolve(data){
        if(self.PromiseState !== "pending") return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
        self.callbacks.forEach(item=>{
            item.onResolved(data);
        });
    }
    function reject(data){
        if(self.PromiseState !== "pending") return;
        self.PromiseState = "fulfilled";
        self.PromiseResult = data;
        self.callbacks.forEach(item=>{
            item.onRejected(data);
        });
    }
    try{
        executor(resolve, reject);
    }catch(err){
        reject(err);
    }
}
Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    return new Promise((resolve, reject) => {
        if(self.PromiseState === "fulfilled"){
            try{
                let result = onResolved(self.PromiseResult);
                if(result instanceof Promise){//如果result是一个Promise对象,那么其本身的state已经定了,没有异步问题
                    result.then((value)=>{
                        resolve(value);
                    }, reason=>{
                        reject(reason);
                    });
                }
                else{
                    resolve(result);
                }
            }catch(err){
                reject(err);
            }
        }
        if(self.PromiseState === "rejected"){
            try{
                let result = onRejected(self.PromiseResult);
                if(result instanceof Promise){//如果result是一个Promise对象,那么其本身的state已经定了,没有异步问题
                    result.then((value)=>{
                        resolve(value);
                    }, reason=>{
                        reject(reason);
                    });
                }
                else{
                    resolve(result);
                }
            }catch(err){
                reject(err);
            }
        }
        if(self.PromiseState === "pending"){
            self.callbacks.push({
                onRejected: function(){
                    try{
                        let result = onRejected(self.PromiseResult);
                        if(result instanceof Promise){//如果result是一个Promise对象,那么其本身的state已经定了,没有异步问题
                            result.then((value)=>{
                                resolve(value);
                            }, reason=>{
                                reject(reason);
                            });
                        }
                        else{
                            resolve(result);
                        }
                    }catch(err){
                        reject(err);
                    }
                },
                onResolved: function(){
                    try{
                        let result = onResolved(self.PromiseResult);
                        if(result instanceof Promise){//如果result是一个Promise对象,那么其本身的state已经定了,没有异步问题
                            result.then((value)=>{
                                resolve(value);
                            }, reason=>{
                                reject(reason);
                            });
                        }
                        else{
                            resolve(result);
                        }
                    }catch(err){
                        reject(err);
                    }
                }
            });
        }
    });
}

9.6 catch与异常穿透

catch就是对then里面的onRejected的单独封装,所以什么功能都可以直接交给then来处理,返回值也是

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

但是这样的话then里面的onResolved就是undefined,会报错,所以我们需要在then中加上

if(typeof onResolved !== "function"){
    onResolved = value => value;
}

异常穿透就是链式的then中只用写一个onResolved,只需要在then中加上

if(typeof onResolved !== "function"){
   onRejected = reason => {
       throw reason;
   }
}

当我们使用链式的then没写onResolved的时候,就会用这个自动补上,下面是一个异常穿透的代码

p3.then(value=>{
    console.log("get users");
}).then(value=>{
    throw "error";
}).catch(reason=>{
    console.log(reason);
})

9.7 构造函数的四个方法

Promise.resolve = function(value){
    return new Promise((resolve, reject) => {
        if(value instanceof Promise){
            value.then(v => {
                resolve(v);
            }, r => {
                reject(r);
            })
        }
        else{
            reject(value);
        }
    });
}
Promise.reject = function(reason){
    return new Promise((resolve, reject) => {
        reject(reason);
    });
}
Promise.all = function(promises){
    return new Promise((resolve, reject) => {
        let count = 0;
        let arr = [];
        for(let i = 0; i < promises.length; i++){
            promises[i].then(value => {
                count++;
                arr[i] = value;
                if(count === promises.length){
                    resolve(arr);
                }
            }, reason => {
                reject(reason);
            }); 
        }
    });
}
Promise.race = function(promises){
    return new Promise((resolve, reject) => {
        for(let i = 0; i < promises.length; i++){
            promises[i].then(value => {
                resolve(value);
            }, reason => {
                reject(reason);
            })
        }
    });
}

9.8 class类的封装

class Promise{
    constructor(executor){
        const self = this;
        this.PromiseState = "pending";
        this.PromiseResult = "";
        this.callbacks = [];
        function resolve(data){
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "fulfilled";
            self.PromiseResult = data;
            setTimeout(() => {
                self.callbacks.forEach(item=>{
                    item.onResolved(data);
                });   
            });
        }
        function reject(data){
            if(self.PromiseState !== "pending") return;
            self.PromiseState = "fulfilled";
            self.PromiseResult = data;
            setTimeout(() => {
                self.callbacks.forEach(item=>{
                    item.onRejected(data);
                });
            });
        }
        try{
            executor(resolve, reject);
        }catch(err){
            reject(err);
        }
    }
    then(onResolved, onRejected){
        const self = this;
        if(typeof onResolved !== "function"){
            onResolved = value => value;
        }
        if(typeof onResolved !== "function"){
            onRejected = reason => {
                throw reason;
            }
        }
        return new Promise((resolve, reject) => {
            function callback(type){
                try{
                    let result = type(self.PromiseResult);
                    if(result instanceof Promise){//如果result是一个Promise对象,那么其本身的state已经定了,没有异步问题
                        result.then((value)=>{
                            resolve(value);
                        }, reason=>{
                            reject(reason);
                        });
                    }
                    else{
                        resolve(result);
                    }
                }catch(err){
                    reject(err);
                }
            }
            if(self.PromiseState === "fulfilled"){
                setTimeout(() => {
                    callback(onResolved);
                });
            }
            if(self.PromiseState === "rejected"){
                setTimeout(() => {
                    callback(onRejected);
                });
            }
            if(self.PromiseState === "pending"){
                self.callbacks.push({
                    onRejected: function(){
                        callback(onRejected);
                    },
                    onResolved: function(){
                        callback(onResolved);
                    }
                });
            }
        });
    }
    catch(onRejected){
        return this.then(undefined, onRejected);
    }
    static resolve(value){
        return new Promise((resolve, reject) => {
            if(value instanceof Promise){
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            }
            else{
                reject(value);
            }
        });
    }
    static reject(reason){
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    }
    static all(promises){
        return new Promise((resolve, reject) => {
            let count = 0;
            let arr = [];
            for(let i = 0; i < promises.length; i++){
                promises[i].then(value => {
                    count++;
                    arr[i] = value;
                    if(count === promises.length){
                        resolve(arr);
                    }
                }, reason => {
                    reject(reason);
                }); 
            }
        });
    }
    static race(promises){
        return new Promise((resolve, reject) => {
            for(let i = 0; i < promises.length; i++){
                promises[i].then(value => {
                    resolve(value);
                }, reason => {
                    reject(reason);
                })
            }
        });
    }
}

10 async与await

10.1 介绍

async就是异步的意思,我们可以将一个异步任务当成同步的任务来执行,比一般的回调函数更为简洁好用,在实现这一功能之前,我们先要了解这两个关键字的基本特点

10.2 async

async就是一种申明函数的关键字,也就是将一个函数申明为异步的函数。

async functiuon sss(){}
sss();

10.3 await

  1. await必须使用在异步函数里面
  2. 右侧一般是promise对象,也可以是一般的值
  3. 如果是promise对象,返回值就是promise成功的值,如果是一个失败的promise对象,那么我们需要使用try catch来接收这个失败的值
  4. 如果是一般的值,那么返回结果就是这个值

10.4 实战

这里使用了ajax的封装函数,可以回到上面再看一下,似乎axios也有这个封装函数

let btn = document.querySelector("button");
btn.addEventListener("click", async () => {
    try{
	    let content = await sendAJAX("http://127.0.0.1:8000/temp");
	    btn.innerHTML = content.name;
    }
    catch(error){
    	console.warn(error);
    }
});

而原本的promise.then的写法就是

btn.addEventListener("click", () => {
	sendAJAX("http://127.0.0.1:8000/temp").then(value=>{
		console.log(value.name);
	}, reason => {
	    console.log(reason);
	})
}

似乎也没有怎么简便

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值