node中的promise

  • Promise是一个类,使用的时候需要new Promise来产生一个promise实例
  • 构造函数中需要传递一个参数 executor
  • xecutor函数中有两个参数 resolve(value) reject(reason)
  • 调用resolve会让promise变成成功 调用reject会变成失败 pending等待态 fulfilled 成功态 rejected失败态
  • 一但状态发生变化后不能再修改状态
  • 每个promise实例都有一个then方法,会有两个参数 onfulfilled, onrjected
  • 如果不调用resolve此时promise不会成功也不会失败 (如果发生异常也会认为是失败)
  • resolve之后 不能reject 相反也是
  • executor是立刻执行的
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('ok')
    },100000)
})
promise.then((value) => {
    console.log('成功1', value)
}, (reason) => {
    console.log('失败1', reason)
});
promise.then((value) => {
    console.log('成功2', value)
}, (reason) => {
    console.log('失败2', reason)
});

promise链式调用

  • 返回的是一个普通值(非promise的值)

    • 返回的是一个普通值(非promise的值)这个值会被传到外层then的下一个then的成功中去
    • 没有返回值(抛错了),会执行外层的then的下一个then的失败
  • 返回的是一个promise

    • 会去解析返回的promise将解析后的值,传递到成功或者失败中(看这个promise是什么状态)
    • 什么时候会失败
      • 抛错走下一次的失败
      • 返回的是失败的promise会走失败
  • promise为了能扭转状态 而且还要保证promise状态变化后不可以更改。 返回一个全新的promise

实现promise

promise.js

console.log('my promise run')
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED'
// 此函数主要的目的是判断x 是不是promise
// 规范中说明 我们的promise可以和别人的promise互通
function resolvePromise(x, promise2, resolve, reject) {
    // 用x 的值来决定promise2 是成功还是失败 (resolve,reject)
    if (x === promise2) {
        return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>] error'))
    }
    // promise实例要么是对象要么是函数
    if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
        let called = false
        try {
            let then = x.then;// 看是否有then方法
            if (typeof then === 'function') {
                // 不用每次都取值了,直接用上次取到的结果
                then.call(x, (y) => {  // 别人家的promise
                    if (called) return
                    called = true
                    resolvePromise(y,promise2,resolve,reject)
                }, (r) => {
                    if (called) return
                    called = true
                    reject(r)
                })
            } else {
                resolve(x); // {then:{}}  | {} | function
            }
        } catch (e) { // 别人家的promise
            if (called) return
            called = true
            reject(e); // 取值出错
        }
    } else { // 说明x是一个普通值
        resolve(x); // 普通值直接向下传递即可
    }
}
class Promise {
    constructor(executor) {
        // 默认promise的状态
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolveCallbacks = [];
        this.onRejectedCallbacks = [];
        const resolve = (value) => {
            //  只有pending状态才可以修改状态
            if (this.status === PENDING) {
                this.value = value;
                this.status = FULFILLED;
                this.onResolveCallbacks.forEach(fn => fn())
            }
        }
        const reject = (reason) => {
            if (this.status === PENDING) {
                this.reason = reason
                this.status = REJECTED;
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }
        try { // 如果executor执行发生异常 就默认等价reject方法
            executor(resolve, reject);
        } catch (e) {
            reject(e)
        }
    }
    then(onFulfilled, onRejected) {
        // then方法中如果没有传递参数 那么可以透传到下一个then中
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected:(reason) => {
            throw reason
        }
        let promise2 = new Promise((resolve, reject) => {
            // ...
            if (this.status === FULFILLED) {
                process.nextTick(() => {
                    try {
                        let x = onFulfilled(this.value)
                        resolvePromise(x, promise2, resolve, reject)
                    } catch (e) {
                        console.log(e)
                        reject(e)
                    }
                })
            }
            if (this.status === REJECTED) {
                process.nextTick(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(x, promise2, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            }
            if (this.status === PENDING) { // 调用then的时候promise没成功也没失败
                this.onResolveCallbacks.push(() => {
                    // todo...
                    process.nextTick(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(x, promise2, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
                this.onRejectedCallbacks.push(() => {
                    process.nextTick(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(x, promise2, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            }
        })
        return promise2
    }
}
Promise.deferred = function () {
    const dfd = {}
    dfd.promise = new Promise((resolve, reject) =>{
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd;
}
// npm install promises-aplus-tests -g
module.exports = Promise

静态方法

Promise.resolve

  • Promise.resolve 是ECMAScript自己实现的(为了能快速创建promise并且具备等待效果)
  • romise.resolve 有一个特点就是会产生一个新的promise, 如果你传入的值是一个promise
  • Promise.resolve 可以解析传入的promise 具备等待效果

Promise.reject

  • 不具备等待

catch

  • 错误可以通过catch来捕获,实际上是then(第一个参数为null)

Promise.all

  • Promise.all 等待所有的promise都成功才成功,有一个失败就失败了
// 都成功才成功,有一个失败就失败了
Promise.all = function (values) {
    return new Promise((resolve, reject) => {
        let idx = 0;
        let result = [];
        values.forEach((item,i) => {
            Promise.resolve(item).then((val) => {
                result[i] = val; // 数组的长度不准确, 用索引映射成功的结果
                if (++idx === values.length) {
                    resolve(result)
                }
            },reject)// 如果任何一个promise失败了那么all就失败了
        })

    })
}

Promise.race

  • 哪个结果快就用谁的,用它来中断成功的结果
Promise.race = function (values) {
    return new Promise((resolve, reject) => {
        values.forEach((item,i) => {
            Promise.resolve(item).then(resolve,reject)// 如果任何一个promise失败了那么all就失败了
        })
    })
}

超时处理

  • 超时处理:由于promise.race中有一个失败了就失败了,所以要想让一个成功的promise,延迟x秒失败的话,就可以构建一个reject和原有的promsie,放入Promise.race中
// 可以自己构建一个promise,和用户写的放在一起,如果我想让用户的失败,我就让内置的promise失败就可以了
let abort

function withAbort(userPromise) {
    let abort;
    const internalPromise = new Promise((resolve, reject) => {
        abort = reject
    })
    let p = Promise.race([userPromise,internalPromise])
    p.abort = abort
    return p
}
let p = new Promise((resolve, reject) => {
    // abort = reject;
    setTimeout(() => {
        resolve(100)
    }, 3000)
})
p = withAbort(p)
setTimeout(() => {
    p.abort('超时了')
},2000)
p.then(data => {
    console.log(data)
}).catch(err => { // 如何让这个promise 走向失败?
    console.log(err,'error')
})

Promise.allSettled

es10中提供的,无论成功和失败都要结果

Promise.allSettled() 不会在任何 Promise 被拒绝时中止,并且总是等待所有 Promise 对象都已解决或拒绝后才返回结果

  • status:表示 Promise 的状态,可能的值为 “fulfilled”(已解决)或 “rejected”(已拒绝)。
  • value:如果 Promise 已解决,则为解决值;如果 Promise 已拒绝,则为拒绝原因。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'error'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 200, 'resolved'));

Promise.allSettled([promise1, promise2, promise3])
  .then((results) => {
    results.forEach((result) => {
      console.log(result.status); // 输出 "fulfilled", "rejected", "fulfilled"
      console.log(result.value); // 输出 3, "error", "resolved"
    });
  });

Promise.xxx.finally

  • 无论成功和失败都要执行的逻辑
// 无论成功和失败都要执行的逻辑 
Promise.prototype.finally = function (fn) {
    return this.then((val) => {
        // Promise.resolve 具备一个功能,就是可以解析传入的promise
        return  Promise.resolve(fn()).then(()=>val)
    }, (r) => {
        return Promise.resolve(fn()).then(()=>{throw r})
    })
}
Promise.resolve('abc').finally(() => { // 无论成功还是失败都会执行
    return new Promise((resolve, reject) => {
        setTimeout(()=>{resolve('abcasdasda')},1000)
    })
}).then((value) => {
    console.log('成功',value)
}).catch((value) => {
    console.log('失败',value)
})
// promise 解析过程 一个promise 返回一个promise才会有等待效果,会采用返回的promise的状态作为下一次then的结果

promisify

将遵循 Node.js 回调风格的函数转换为返回 Promise 的函数

只针对node 因为node中函数参数,第一个永远是错误, 基于传递的参数构建promise

function promisify(fn) { // 高阶函数
    return (...args) => {
        return new Promise((resolve, reject) => {
            fn(...args, function (err, data) {
                if (err) return reject(err)
                resolve(data)
            })
        })
    }
}
function promisifyAll(obj) { // 转化对象中所有的api
    for (let key in obj) {
        const val = obj[key]
        if (typeof val === 'function') {
            obj[key] = promisify(val)
        }
    }
}

generator生成器

  • 生成器,在生成的过程中可以暂停,可以自己控制是否继续
  • 生成器是用来生成迭代器
  • yield的返回值是下一次调用next传递的参数
function* gen() {
    try {
        let a = yield 1; // js执行是先走等号右边的,遇到yield就停止了
        console.log(a)
        let b = yield 2;// yield的返回值是下一次调用next传递的参数
        console.log(b)
        let c = yield 3
        console.log(c)
        return undefined
    } catch (e) {
        console.log(e)
    }
}
let it = gen(); // iterator 迭代器
console.log(it.next('asdasdasd')); // 第一次调用next方法传递的参数没有任何意义
it.throw('错误'); // 调用了第一次next的时候 可以暂停逻辑,如果觉得这个逻辑有异常后续可以通过throw方法抛出异常
console.log(it.next('abc'));
console.log(it.next('abcd')); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: 4, done: false }

co模块

co 模块 使用 Generator生成器函数 和promise, 让我们以同步的形式写异步代码

  • co是npm的一个包

    function co(it) {
        return new Promise((resolve, reject) => { // 同步迭代for循环,异步迭代用回调
            function next(data) { // koa express
                let { value, done } = it.next(data);
                if (!done) { // 如果没完成返回的一定是一个promise
                    Promise.resolve(value).then((data => {
                        next(data)
                    }),reject)
                } else {
                    resolve(value); // 完成value就是最后的结果
                }
            }
            next();
        })
    }
    

实现generator

generator 的原理就是将一个函数分解成多个 switch case通过指针指向要执行的部分

function wrap(iteratorFn) {
    const _context = {
        next: 0,
        done:false,
        sent: undefined,
        stop() {
            this.done = true;
        }
    }
    return {
        next(value) {
            _context.sent = value; // 先赋值再去调用方法
            let v = iteratorFn(_context); // 执行函数传递上下文 
            return {value:v,done:_context.done}
        },
    }
}
function gen() {
    var a, b, c;
    return wrap(function gen$(_context) {
        switch (_context.prev = _context.next) {
            case 0:
                _context.next = 2;
                return 1;
            case 2:
                a = _context.sent;
                console.log(a);
                _context.next = 6;
                return 2;
            case 6:
                b = _context.sent;
                console.log(b);
                _context.next = 10;
                return 3;
            case 10:
                c = _context.sent;
                console.log(c);
            case 12:
            case "end":
                return _context.stop();
        }
    });
}

let it = gen();
console.log(it.next())
console.log(it.next('abc'))
console.log(it.next('bcd'))
console.log(it.next('bcd'))

// 实现了一个简易的generator ,generator 的原理就是将一个函数分解成多个 switch case通过指针指向要执行的部分

// function* gen() {
//     let a = yield 1;
//     console.log(a)
//     let b = yield 2;
//     console.log(b)
//     let c = yield 3;
//     console.log(c)
// }


async、await

co+generator 就是async+await

  • https://www.babeljs.cn/repl#?browsers=ie%206&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=IYZwngdgxgBAZgV2gFwJYHsIwE4FNgAmASriAgDbIAUAlDAN4BQMLM5uy8q7EwAtrhgBeGMADuwVJzggAdHkIAxbrioAHYMgAW80unIA3VQH1jBVNl4CANDADkV3LOQAPZHZq27CZHAAcHgDczKzsnMAA5oIi4pLScgoEyuzqmjp4IPpGVKbmlvy4tnAqjp72Pv5BISx4yAiWolHBAL5AA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact%2Cstage-0%2Cstage-1%2Cstage-2%2Cflow&prettier=false&targets=&version=7.24.7&externalPlugins=&assumptions=%7B%7D
  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值