Coder Social home page Coder Social logo

blog's People

Contributors

krisguoqin avatar

Watchers

 avatar  avatar

blog's Issues

撤销上一次提交

git commit 之后发现提交错了,如果想撤回提交,使用

git reset --soft HEAD^

通过这种方式就撤销了你的commit

注意,仅仅是撤回commit操作,写的代码仍然保留。

Git 切换远程仓库地址

  1. 命令行修改
git remote set-url origin newUrl

2.修改git文件下的config文件,修改其中的git remote orign
3.命令行修改

git remote rm origin
git remote add origin newUrl

根据Promise A+ 规范实现Promise

Promise是一种异步解决方案,可以有效的解决基于回调函数形式而造成的回调地狱。在ES6中正式成为规范。在工作中会经常用到,同时在面试中也是必考的考点,所以我们不仅仅要掌握它的用法,也要明白它的原理。

Promise规范

Promise规范要求摘要

  1. promise只有三种状态,分别为 pending, fulfilled, rejected。
  2. 状态只能从 pending 变为 fulfilled, 或者从 pending 变为 rejected. 状态不可逆转。
  3. promise接受一个函数作为参数,执行该函数,并为该函数填充resolve, reject两个参数。执行成功调用resolve, 执行失败调用reject。
  4. promise必须提供then方法用于处理状态变更后的结果。并且then方法的返回结果为新的promise。
  5. then方法的参数为 onFulfilled, onRejected .完成状态调用onFulfilled,失败状态调用 onRejected。

Promise源码实现

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const isFunc = params => typeof params === 'function'

class Promise {
    constructor(executor) {
        if (!isFunc(executor)) throw new Error('Promise only accept a function as a parameter')

        // 状态
        this._status = PENDING
        // 数据
        this._value = undefined
        // 成功回调队列
        this._fulfillQueues = []
        // 失败回调队列
        this._rejectQueues = []

        try {
            executor(this._resolve.bind(this), this._reject.bind(this))
        } catch (error) {
            this._reject(error)
        }
    }
    // resolve时候执行的函数
    _resolve(value) {
        if (this._status === PENDING) {
            this._status = FULFILLED
            this._value = value
            // 2.2.2.3 回调函数只能调用一次
            let cb = this._fulfillQueues.shift()
            while(cb) {
                cb(value)
                cb = this._fulfillQueues.shift()
            }
            // 队列被清空
        }
    }
    // reject时候执行的函数
    _reject(reason) {
        if (this._status === PENDING) {
            this._status = REJECTED
            this._value = reason
            // 2.2.3.3 回调函数只能调用一次
            let cb = this._rejectQueues.shift()
            while(cb) {
                cb(reason)
                cb = this._rejectQueues.shift()
            }
            // 队列被清空
        }
    }
    // then
    then(onFulfilled, onRejected) {
        // 2.2.1 onFulfilled, onRejected 都是可选的
        // 2.2.5 onFulfilled, onRejected 必须作为函数调用
        
        // 2.2.7.3 若 onFulfilled ,不是一个函数,当前promise1为完成状态,
        // 那promise2也是完成状态,且值promise1的 value
        // 2.2.7.3 若 onRejected ,不是一个函数,当前promise1为失败状态,
        // 那promise2也是失败状态,且值为promise1的 reason
        onFulfilled = isFunc(onFulfilled) ? onFulfilled : value => value
        onRejected = isFunc(onRejected) ? onRejected : reason => { throw reason }
        const context = this

        // 2.2.7 then必须返回一个promise
        const promise2 = new Promise(function(resolve, reject){
            if (context._status === FULFILLED) {
                // 2.2.2 如果 onFulfilled 是函数,必须在promise1 fulfilled之后调用,其参数为promise1的value
                // 2.2.4 onFulfilled,必须异步的调用
                // 3.1 可以使用微任务 MutationObserver 或者 process.nextTick. 或者使用宏任务 setTimeout , setImmediate.
                setTimeout(() => {
                    try {
                        // 2.2.7.1 如果 onFulfilled, onRejected 返回了值 x ,运行 
                        // the Promise Resolution Procedure [[Resolve]](promise2, x)
                        let x = onFulfilled(context._value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        // 2.2.7.2 如果 onFulfilled, onRejected 抛出了错误,那 promise2 就 reject(error)
                        reject(error)
                    }
                })
                return
            }
            if (context._status === REJECTED) {
                // 2.2.3 如果 onRejected 是函数,必须在promise1 rejected 之后调用,其参数为promise1的value
                // 2.2.4 onRejected ,必须异步的调用
                // 3.1 可以使用微任务 MutationObserver 或者 process.nextTick. 或者使用宏任务 setTimeout , setImmediate.
                setTimeout(() => {
                    try {
                        // 2.2.7.1 如果 onFulfilled, onRejected 返回了值 x ,运行 
                        // the Promise Resolution Procedure [[Resolve]](promise2, x)
                        let x = onRejected(context._value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        // 2.2.7.2 如果 onFulfilled, onRejected 抛出了错误,那 promise2 就 reject(error)
                        reject(error)
                    }
                })
                return
            }
            if (context._status === PENDING) {
                context._fulfillQueues.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(context._value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                })
                context._rejectQueues.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(context._value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                })
            }
        })
        return promise2
    }
    // 用于测试
    // defer
    static defer() {
        return defer()
    }
    static deferred() {
        return defer()
    }
    // promise 规范只要求我们必须实现 then  方法,但是es6规范还要求一些静态方法与实例方法,如
    // 静态方法:Promise.resolve, Promise.reject, Promise.all, Promise.race
    // 实例方法:catch, finally
    // 在ES6标准入门中还有 done 方法,面试题中还有要实现 retry 方法
    // catch
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    // done
    // 总是处于回调链的尾端,保证抛出任何可能的错误
    done(onFulfilled, onRejected) {
        this.then(onFulfilled, onRejected)
            .catch(reason => {
                // 全局抛出一个错误
                setTimeout(() => { throw reason }, 0)
            })
    }
    // finally
    // 和 done 的最大区别是,接受一个普通的回调函数作为参数,该函数不管怎样都会执行
    finally(handle) {
        return this.then(
            value => Promise.resolve(handle()).then(() => value),
            reason => Promise.resolve(handle()).then(() => { throw reason })
        )
    }
    // staic resolve
    static resolve(value) {
        if(value instanceof Promise) return value
        return new Promise(resolve => resolve(value))
    }
    // static reject
    static reject(reason) {
        return new Promise((resolve, reject) => reject(reason))
    }
    // parameter #1, the function to return a Promise
    // parameter #2, the max retry times
    // parameter #3, the delay between each attempt
    static retry(fn, times, delay) {
        return new Promise((resolve, reject) => {
            function attempt() {
                fn().then(resolve)
                    .catch(err => {
                        if (times === 0) {
                            reject(err)
                        } else {
                            times--
                            setTimeout(() => {
                                attempt()
                            }, delay)
                        }
                    })
            }
            attempt()
        })
    }
    // static all
    all(promises) {
        return new Promise((resolve, reject) => {
            let count = 0
            let results = []
            let len = promises.length
            if (!promises.length) {
                // 空的可迭代对象,直接返回
                resolve(results)
            } else {
                for(let i = 0; i < len; i++) {
                    Promise.resolve(promises[i]).then(
                        value => {
                            results[i] = value
                            count++
                            // 所有promise都完成后, resolve
                            if(count === len) resolve(results)
                        },
                        // 有一个发生错误,直接reject
                        error => reject(error)
                    )
                }
            }
        })
    }
    // static race
    race(promises) {
        return new Promise((resolve, reject) => {
            for(let p of promises) {
                // 第一个 Promise 完成或者失败后,直接返回结果
                Promise.resolve(p).then(
                    value => resolve(value),
                    reason => reject(reason)
                )
            }
        })
    }
}
function resolvePromise(promise2, x, resolve, reject) {
    // 2.3.1 如果promise2和x是同一个对象,使用一个 TypeError 来 reject promise
    if (promise2 === x) {
        reject(new TypeError('Chaining cycle'))
    }
    if (x && typeof x === 'object' || isFunc(x)) {
        // 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 都被调用了,或者
        // 相同的参数被多次调用了,那么只取第一次调用,后面的调用忽略掉
        let used;
        try {
            // 2.3.3.1 把 x.then 赋值给 then
            const then = x.then
            // 2.3.3.3 如果then是一个函数,调用它,把x作为this,
            // resolvePromise 作为第一个参数,rejectPromise 作为第二个参数
            if (isFunc(then)) {
                then.call(
                    x,
                    // 2.3.3.3.1 如果/当使用值y来调用resolvePromise时候,运行
                    // resolvePromise(promise2, y, resolve, reject)
                    y => {
                        if(used) return
                        used = true
                        resolvePromise(promise2, y, resolve, reject)
                    },
                    // 2.3.3.3.2 如果/当使用值r来调用 作为第一个参数,rejectPromise 时候,使用
                    // 值 r 来 reject promise
                    r => {
                        if(used) return
                        used = true
                        reject(r)
                    }
                )
            } else {
                // 2.3.3.4 如果 then 不是函数,使用 x 来 fulfill promsie
                if(used) return
                used = true
                resolve(x)
            }
        } catch (error) {
            // 2.3.3.2 如果 2.3.3.1发生了错误,使用error来reject promise
            if(used) return
            used = true
            reject(error)
        }
    } else {
        // 2.3.4 如果 x 不是对象或函数, 使用 x 来 fulfill promsie
        resolve(x)
    }
}
function defer() {
    const dfd = {}
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd
}
module.exports = Promise

Rxjs应用:先并发再串行

需求背景

有一个表单,上面有上传图片和上传附件的功能,还有一些表单字段需要填写,最后提交表单。共有三个接口,上传图片接口,上传附件的接口,提交表单数据的接口。需要实现先上传图片和附件,获取到上传的地址后提交表单。

代码实现

import { from, zip } from 'rxjs';
import { concatMap } from 'rxjs/operators';

const makePromise = (name, delay) => new Promise((resolve, reject) => setTimeout(() => resolve(`${name} done`), delay));

const uploadImgs$ = from(makePromise('uploadImgs', 1000));
const uploadFiles$ = from(makePromise('uploadFiles', 2000));
const submitForm$ = from(makePromise('submitForm', 1000));

const subInst = zip(
    uploadImgs$,
    uploadFiles$
).pipe(
    concatMap(val => {
        console.log('val', val);
        return submitForm$
    })
).subscribe(
    data => {
        console.log('data', data)
    },
    error => {
        console.log('error', error)
    }
);

// async await实现
async function submitForm () {
    const val = await Promise.all([
        makePromise('uploadImgs', 1000),
        makePromise('uploadFiles', 2000)
    ]);
    console.log('val', val);
    const val2 = await makePromise('submitForm', 1000);
    console.log('val2', val2);
}
submitForm()

解读

实现的关键在于zip创建符。它的作用类似于我们衣服的拉链咬合的过程。会将我们输入的Observable组合起来,等待所有的的Observable每次完成之后输出结果,因为我们的只运行一次就结束了,所有只输出一次结果。它运行的时间取决于耗时最长的那个。待我们拿到结果后,可以结果传给另一个Observable,因为要继续处理Observable,所有我们需要用到高阶Observable。高阶Observable和高阶函数**类似。输入Observable,返回Observable,我们的操作符会自动订阅返回的Observable,并将最终结果输出。

上面的代码假设uploadImgs$ 耗时1s,uploadFiles$耗时2s。所以zip处理的时间为2s,2s后将结果返回给下游。下游收到数据后,经过submitForm$处理,1s后返回结果。整个过程耗时3s多。

另外,zip除了可以作为静态方法外,还可以作为操作符;我们也可以mergeMap来处理高阶Observable。在这个实例中没有大的区别。

实际中,常用的都是ajax请求,这个实例为了演示使用了setTimeout。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.