写给小白的手写promise源码

Promise-A-Plus:纯 TypeScript 手写 Promise A+ 手写 Promise A+ English: 术语 解决(fulfill) 指的是一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。虽然规范中使用 fulfill 来表示解决,但是目前常用 resolve 来取代。 拒绝(reject) 指的是一个 promise 失败时进行的操作。 终值(eventual value) 所谓终值,指的是 promise 被解决是传递给解决回调的值,由于 promise 有一次性的特征,因此当这个值被传递的时候,标志着 promise 等待态的结束,故称之为终值,也简称为值(value)。 据因(reason) 拒绝的原因,指的是 promise 被拒绝是传递给拒绝回调函数的值。 Promise 的状态 一个 Promise 的当前状态必须为以下三种状态中的一种 等待态(pending) 处于等待态时,promise 可以迁移至执行态 立即下载

认识promise

promise是解决异步编程的一种方案,可以解决回调地狱等问题,promise是有状态的,它的状态就决定了会执行哪一个回调函数,以下面的例子来解释

  • 下面代码封装了一个ajax调用的函数,使用promise封装,最后会返回一个promise实例
  • 若接口调用成功,就会执行promise里的resolve这个方法,使promise状态变为成功的,否则执行reject,promise状态变为失败,若都没有执行以上两个方法的话,promise的状态就是peding等待
  • promise的状态就决定了then方法会执行哪个回调,成功的就会执行第一个,失败执行第二个
function myAjax(url)
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttprequest()
        xhr.open('get', url)
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4 && xhr.status == 200) {
                resolve('接口调用成功!')
            } else {
                reject('接口调用失败!
            }
        }
            xhr.send()
    })
}
                       
myAjax('http://127.0.0.1').then(r => {
   // 这里执行成功的回调 
}, e => {
   // 这里执行失败的回调 
})

promise三个状态

  • pending:初始状态,即没有成功,也没有失败
  • fulfilled:意味着操作成功
  • rejected:意味着操作失败

promise状态改变时不可逆的,被创建的 promise 最终会以被解决状态 (fulfilled) 或 被拒绝状态(rejected) 结束,且状态只会改变一次

另外,规定必须给Promise对象传入一个执行函数,否则将会报错!

常见promise API

then

const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('settimeout111')   
            })
        })
p.then(res => {
            console.log(res);
        }, err =>{
    console.warn(err)
})
  • 可以传入2个回调函数,若该Promise成功时执行第一个函数,失败时执行第二个
  • 一个promise可以支持多次执行then方法
  • 执行then方法后会返回一个promise实例,
  • then无论执行成功的还是失败的回调,若执行后没有返回值,则会返回一个成功的promise, promiseresult为undefined
  • 若then里面有返回值, 且返回值不是promise,则也会返回一个成功的promise, promiseresult为返回的值
  • 若返回了一个Promise, 则会根据该promise状态来决定then返回的promise的状态
  • 若在then里面抛出一个错误后,则会返回一个失败的promise

catch

  • promise为失败时会执行
  • promise异常穿透

Promise.resolve()

  • 会返回一个promise
  • 若接受的参数不是promis对象,则会返回一个成功的promise
  • 若接收的参数为一个promise对象,则返回的promise状态会由该对象决定

Promise.reject()

  • 同样返回一个promise
  • 无论该参数是否为promise,最后都会返回一个失败的promise

all

  • 返回一个promise
  • 参数为一个数组,数组元素都是promsie对象
  • 若该数组中有失败的promise,则返回一个失败的promise, promiseResult为该失败Promise的结果
  • 若数组中都是成功的promise, 则返回一个成功的promise, promiseResult为由这些promsie结果组成的数组

race

  • 返回一个promise
  • 参数为一个数组,数组元素都是promsie对象
  • 会根据参数中第一个完成的promise的状态决定返回的promise成功或失败

源码分析

初始结构

  • 使用类创建一个myPromise类,用常量定义三个状态

  • promise会传入一个执行器函数,初始化的时候执行该函数,并先使promise状态设置为pending

  • 执行器函数定义了两个形参,分别为resolve, reject,而我们在调用用户传入的执行器函数之后,会把这两个形参换成resolve, reject这两个在promise内部实现好的方法

  • 由于执行器函数是用户定义的,resolve和reject方法也不知道会在什么地方使用,由于调用的不确定性,就会产生this的执行问题,所以需要绑定在myPromise实例上,才会有这两个方法

  • 代码如下

// 用常量定义三个状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class myPromise {
    PromiseState = ''
	constructor(execute) {
        initial(execute)
    }
	// 初始化
	initial(execute) {
        this.PromiseState = PENDING
        // 执行执行器函数,传入resolve, reject方法,并绑定this
        execute(this.resolve.bind(this), this.reject.bind(this))
    }
	resolve() {}
	reject() {}
	
}

实现resolve和reject方法

一开始,我并不知道这两个方法会怎么被实现,但到后面才逐渐理解,用户传入的执行器函数相当于是定义了函数的内容,这个函数会由promise来决定执行的时机,执行器函数里面的两个参数,在promise里面,会被替换成我们自己定义的resolve和reject方法,但这两个方法到底执行哪一个,跟执行器函数的定义有关,比如执行器里面会执行第一个参数,就会执行我们定义的resolve方法

执行resolve还是reject?

笼统来说,使用promise时,promise状态为成功时,执行resolve方法,状态为失败时,执行reject方法,但成功与否还是由用户和具体语义决定,比如,我们调用ajax接口,接口调用成功即为成功,执行resolve方法,否则执行reject方法

  • 执行之后,该promise实例状态就会改变,所以在这两个方法中要改变promise状态
  • 这两个方法有一个参数,用来接受用户主动传入的数据,比如ajax调用之后,用户想要拿到调用的结果,就可以把这个结果作为reject或resolve的参数,我们在实例中需要去接收这个参数,并赋值给PromiseResult实例
  • promise状态只能改变一次,也就是说,如果有多个resolve或者reject方法,它只会根据代码的执行顺序执行第一个,所以在这两个方法中需要判断promsie状态,若状态不为pending时,即表示已经执行过这两个方法了,则退出什么也不做
  • 最后,若执行器函数里代码出现错误的话,会执行reject方法,将promsie状态变为REJECTED,所以要在初始化方法initial中执行器执行里面捕获错误,并将错误原因作为PromiseResult
  • 代码如下:
resolve(value) {
    // 先判断状态
    if(this.PromiseState != PENDING) return
    this.PromiseState = FULFILLED
    this.PromiseResult = value
}

reject(error) {
    if(this.PromiseState != PENDING) return
    this.PromiseState = REJECTED
    this.PromiseResult = value
}

// 初始化
	initial(execute) {
        this.PromiseState = PENDING
        // 捕获错误
        try {
           // 执行执行器函数,传入resolve, reject方法,并绑定this
        	execute(this.resolve.bind(this), this.reject.bind(this))
        } catch(e) {
            reject(e)
        }
       
    }

实现then方法

按照我们使用promise的惯例,我们之后就要使用then方法来处理我们接受到的结果了,then方法的具体用法已经写在上面了,忘记了的可以自行翻阅

在then方法里面,我们一般会传入一个成功的回调,但其实是可以传入两个回调的,第一个是成功的,第二个是失败的(通常在catch方法中处理),手写过程如下:

  • 先在myPromise类中定义一个then方法,接受两个参数,第一个为onFulfilled函数,第二个为onRejected函数,用来分别接收用户传入的成功的和失败的回调,同时,这两个参数函数同时也需要参数,这个参数就是执行器函数中传给resolve或reject方法的数据,我们已经用PromiseResult接收了
  • 具体执行哪一个回调,需要依据promise状态来决定,所以在then方法中要用this.PromiseState判断promise的状态来决定执行哪一个回调函数
  • 具体代码如下:
then(onFulfilled, onRejected) {
    if(this.PromiseState == FULFILLED) {
        onFulfilled(this.PromiseResult)
    } else if(this.PromiseState == REJECTED) {
        onRejected(this.PromiseResult)
    }
}

回调收集

至此,我们已经实现了简易版的then了,但肯定在学习event loop的时候给promise添加了定时器,那如果我们现在在myPromise里面添加定时器会怎样,如下面:

// 猜猜会输出什么?
new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('OK')
    })
}).then(r => {
    console.log(r)
}, e => {
    console.warn(e)
})

答案是什么都不会输出!让我们来分析一下:

  • new完之后,就会执行执行器内的函数,里面是一个定时器,而定时器是一个异步任务(代码),所以js会先跳过去执行同步代码
  • 所以就会执行到then方法,**但是,此时并没有执行resolve或者reject方法中的一个,所以promise的状态仍为pending!**而我们then方法中并没有对状态为pending的判断

保存回调函数

我们的原意是能在then里面处理promise异步代码里传入的数据,那既然then方法已经在异步代码之前已经执行完了,所以肯定不能在then里面处理了。仔细思考一下,异步代码执行时会干什么?

是不是会执行resolve或者reject方法,那我们就可以**把then里面的回调函数收集起来,在resolve或者reject方法中执行!**具体做法如下:

  • 定义两个数组,命名为onFulfilledCallbacks和onRejectedCallbacks,用来保存then方法中的成功和失败的回调,这里为什么要用数组呢?是因为我们new一个实例p,可以多次执行p.then方法,所以都要把这些回调都收集起来
  • 接着,在reslolve或者reject方法中,要判断这两个数组是否为空,不为空的话需要遍历执行每一个回调函数,并传入PromiseResult
  • 具体代码如下:
class myPromise {
    ...
    constructor() {
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []
        ...
    }
    resolve(value) {
        ...
        // 执行回调
        if(this.onFulfilledCallbacks.length) {
            onFulfilledCallbacks.forEach(fn => {
                fn(this.PromiseResult)
            })
        }
    } 

	reject(error) {
        ...
        if(this.onRejectedCallbacks.length) {
           onRejectedCallbacks.forEach(fn => {
                fn(this.PromiseResult)
            }) 
        }
    }

	then(onFulfilled, onRejected) {
        // 状态为pending时收集回调
        if(this.PromiseState == PENDING) {
            this.onFulfilledCallbacks.push(onFulfilled)
            this.onRejectedCallbacks.push(onRejected)
        }
        ...
    }
	
}

实现异步

我们都知道,then方法需要异步执行,比如下面这段代码,会先输出end,再输出OK123,但是,我们现在的myPromise还不能实现这一点

new Promise((resolve, reject) => {
    resolve('OK123')
}).then(r => {
    console.log(r);
})
console.log('end')

具体做法是给then方法加上定时器模拟异步,但因为定时器是一个宏任务,而then其实是一个微任务,所以可以利用mutation observer或者process.nextTick模拟一个微任务,代码如下:

then(onFulfilled, onRejected) {
    if(this.PromiseState == FULFILLED) {
        setTimeout(() => {
            onFulfilled(this.PromiseResult)
        })
    } else if(this.PromiseState == REJECTED) {
        setTimeout(() => {
            onRejected(this.PromiseResult)
        })   
    }
    ...
}

链式调用

链式调用就是一直点点点下去,如下面的代码,可以用来解决回调地狱的问题

new Promise((resolve, reject) => {
    resolve('OK')
}).then(r => {
    console.log(r)
}).then(r => {
    console.log(r)
})

那么,then方法的链式是怎么实现的呢,我们看到,在执行完then方法之后,我们还可以接着使用promse提供的then,这就说明了**then方法执行完之后还是返回一个promise实例!**then方法返回怎么样的promse实例,具体的规则如下

  • then返回的promsie实例的状态由then方法里面执行的回调函数有关,也就是跟onFufilled和onRejected有关

  • 若then方法里面的回调函数没有返回值或者返回的不是一个promse实例,则then方法返回一个成功的promise实例,promiseResult为回调函数返回的结果

  • 若回调函数里面返回的是一个promsieA,则then方法返回的promise状态由这个promsieA决定,A是成功的则返回成功的promise,失败的则返回失败的promise

  • 若回调函数里面抛出错误,则返回一个失败的promsie实例

既然知道了规则,那我们就来开始写吧!先给出我们之前写过的then方法

then(onFulfilled, onRejected) {
    if(this.PromiseState == PENDING) {
        this.onFulfilledCallbacks.push(onFulfilled)
        this.onRejectedCallbacks.push(onRejected)
    } else if(this.PromiseState == FULFILLED) {
        setTimeout(() => {
            onFulfilled(this.PromiseResult)
        })
    } else {
        setTimeout(() => {
            onRejected(this.PromiseResult)
        })   
    }
    ...
}
  • 首先不管三七二十一,先返回一个promise

    then() {
        return myPromise((resolve, rejecte) => {
            
        })
    }
    
  • 这里要记住,promise里面的代码时同步代码,所以会先执行完里面的代码

  • then返回的promsie状态其实是看这里到底执行resolve或者reject方法,所以接下来就是要判断到底执行resolev或者reject

  • 先思考then方法判断状态不为pending的情况,这种情况下我们会直接执行onFulfilled或者onRejected函数,我们要看看这两个函数返回的结果是什么,判断是否为promise,若不是promise,则直接执行resolve函数,记得把参数传进去

  • 若返回的结果是promsie,则需要判断该promsie的状态,那怎么判断呢,是不是可以通过then方法判断,若执行第一个回调则是成功的,第二个回调则是失败的,我们只需要把resolve和reject放在这两个函数中执行就好了

  • 若是抛出错误的情况,则直接捕获,执行reject

  • 具体代码如下

    then(onFulfilled, onRejected) {
        if(this.PromiseState == PENDING) {
            this.onFulfilledCallbacks.push(onFulfilled)
            this.onRejectedCallbacks.push(onRejected)
        } else if(this.PromiseState == FULFILLED) {
            setTimeout(() => {   
                // 捕获错误
                try {
                    // 判断回调的结果是否是promise实例
                    const result = onFulfilled(this.PromiseResult)
                    if(result instanceof myPromise) {
                        myPromise.then(r => {
                            resolve(r)
                        }, e => {
                            reject(e)
                        })
                    } else {
                        resolve(result)
                    }
                } catch(e) {
                    reject(e)
                }
            })
        } else {
            // 写法和上面一样,就不写了。
            setTimeout(() => {
                onRejected(this.PromiseResult)
            })   
        }
    }
    
  • 接着,来实现then里面判断状态为pending的时候了

  • 之前,我们是把回调函数直接放在数组里面,但这样的话还是没有能够判断回调函数里面执行的是什么,所以还是得跟上面的操作一样,判断回调的结果是否是promise等,具体代码如下:

    then() {
        ...
        if (this.state == PENDING) {
            // console.log('当前状态为pending状态!');
            this.onFulfilledCallbacks.push.push(
                onFullfiled: () => {
                    try {
                        // console.log(this);
                        const result = onFullfiled(this.PromiseResult)
                        if(result instanceof myPromise) {
                            result.then(res => {
                                resolve(res)
                            }, err => {
                                reject(err)
                            })
                        } else {
                            resolve(result)
                        }
                    } catch(e) {
                        // console.log('成功的回调', e);
                        reject(e)
                    }
                }),
                // 写法也是一样的,就不重复了
                onRejected: () => { }                
    }
    
  • 注意,这里会把resolve和reject传入到回调函数里面去,所以也涉及到闭包的问题

  • 至此,then方法就算完成啦!!!

封装resolvePromise

上面书写的过程中,细心的朋友就会发现,我们写了三段重复的代码,所以可以封装成一个函数减少重复代码

  • 首先这个函数需要有四个参数,第一个是promise2,为then方法要返回的promise,所以我们不能像之前写的那样直接返回一个promise,得先用一个变量promise2声明我们要返回的promise,再返回promise2;然后第二个参数是x,表示的是onFulfilled或者onRejected返回的结果,即then方法回调返回的结果,第三个参数为resolve,即promise2的resolve方法,用来改变promsie2状态的,同理第四个参数是reject

  • 所以,我们先在then函数里面改用这个函数,再来写这个函数的具体代码

  • 修改后的then如下:

    then(onFulfilled, onRejected) {
        const promise2 = new myPromise((resolve, reject) => {
            if(this.PromiseState == FULFILLED){
                setTimeout(() => {
                        try {
                        	const x = onFulfilled(this.PromiseResult)
                        	resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        reject(e)
                    }
                })
            }
        })
        return promise2
    }
    
  • 接着,我们把这个函数简单实现一下

/**
 * 
 * @param {promise} promise2  then方法返回的promise
 * @param {*} x then的回调返回的结果
 * @param {*} resolve promise2的resolve方法
 * @param {*} reject  promise2的reject方法
 */
function resolvePromise(promise2, x, resolve, reject) {
    if(x instanceof myPromise) {
        if(x.PromiseState == PENDING) {
            x.then(v => {
                resolve(v)
            }, e => {
                reject(e)
            })
            // 与上面写法不同的是这样写的话当x的状态已经确定的话就不用去执行x.then方法了
        } else if(x.PromiseState == FULFILLED) {
            resolve(x.PromiseResult)
        } else {
            reject(x.PromiseResult)
        }
    } else {
        resolve(x)
    }
}

写到这里,是不是以为万事大吉了呀,哈哈哈!怎么可能,勤奋好学的我们怎么能止步于此,接下来就按照promiseA+规范把这个函数完整地写出来,大体的思路就是根据x的类型做不同的处理,emmmm大多数我也是按照网上的博客写的,有的也不是很懂,但先写出来吧,等懂了的话再过来修改。。

  • 如果x与promise2相等的话,则抛出一个TypeError错误,虽然这种情况很少见,但封装的过程一定要想到各种情况,下面这种情况就应该报错

    const p = new Promise((r, j) => {
        r('OK')
    })
    const p1 = p.then(r => {
        return p1  // TypeError('chaining cycle detected for promise')
    })
    
  • 如果x是promsie的话,处理的情况就跟之前的差不多

  • 如果x是对象或者是函数的时候,将值x.then赋值给then

    • 如果then是一个函数的话,会去调用这个函数,模拟promise.then方法的执行过程,先将this绑定在x上,再传入两个执行器函数
    • 如果then不是一个函数的话。则直接执行resolve(x)
  • 如果x都不满足上面的情况,即是一个普通的基本数据类型的值的话,则直接执行resolve(x)

  • 具体代码如下:

/**
 * 
 * @param {promise} promise2  then方法返回的promise
 * @param {*} x then的回调返回的结果
 * @param {*} resolve promise2的resolve方法
 * @param {*} reject  promise2的reject方法
 */
function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {
        return reject(new TypeError('Chaining cycle detected for promise'));
    }
    if (x instanceof myPromise) {
         // 与上面写法不同的是这样写的话当x的状态已经确定的话就不用去执行x.then方法了
        if (x.PromiseState === myPromise.PENDING) {
            /**
             * 2.3.2.1 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
             *         注意"直至 x 被执行或拒绝"这句话,
             *         这句话的意思是:x 被执行x,如果执行的时候拿到一个y,还要继续解析y
             */
            x.then(y => {
                resolvePromise(promise2, y, resolve, reject)
            }, reject);
        } else if (x.PromiseState === myPromise.FULFILLED) 
            resolve(x.PromiseResult);
        } else if (x.PromiseState === myPromise.REJECTED) {
            reject(x.PromiseResult);
        }
    } else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        // 2.3.3 如果 x 为对象或函数
        try {
            var then = x.then;
        } catch (e) {
            // 因为可能x并没有then这个属性或者其他情况,所以要捕获错误
            return reject(e);
        }

        /**
         * 2.3.3.3 
         * 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
         * 传递两个回调函数作为参数,
         * 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
         */
        if (typeof then === 'function') {
            // 2.3.3.3.3 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
            let called = false; // 避免多次调用
            try {
                // 这个地方大致是模仿promise.then方法的,但有点看不懂
                then.call(
                    x,
                    y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } catch (e) {
                if (called) return;
                called = true;
                reject(e);
            }
        } else {
            //  then 不是函数
            resolve(x);
        }
    } else {
        // 如果 x 不为对象或者函数,直接执行resolve
        return resolve(x);
    }
}

至此,then方法算是完全写好啦,泪目!

Promise.resolve(value)

接下来,就是实现Promise的几个静态api了,个人觉得,在面试中,不太可能会让你写then方法这么恶心的,而且需要的时间也特别多,反倒是下面这几个常见的api手写的概率会比较多,因为大多是借助then方法来实现的,写起来花费的时间也不会很多

Promise.resolve有以下几个特点:

  • 返回一个promsie,如果value是promise的话,状态由value决定

  • 如果value是一个普通值的话,则这个promise状态就是成功的

  • 具体代码

static resolve(value) {
    return new myPromise((resolve, reject) => {
        if(value instanceof myPromise) {
                value.then(res => {
                    resolve(res)
                }, err => {
                    reject(err)
                })
            } else {
                resolve(value)
            }
    })
}

Promise.reject(value)

无论什么情况,都返回一个失败的promise,代码如下

static reject(value) {
     return new myPromise((resolve, reject) => {
        if(value instanceof myPromise) {
                value.then(res => {
                    reject(res)
                }, err => {
                    reject(err)
                })
            } else {
                reject(value)
            }
    })
}

Promise.all()

  • 接收一个由promise实例组成的数组,并返回一个promsie
  • 返回的promise状态由接收的promise实例的状态决定,若数组中出现一个promsie失败的情况,则返回一个失败的promsie,若数组中的promise实例都是成功的,则返回一个成功的promise,promiseResult为各个promsie实例返回的值的组合
  • 具体代码如下:
static all(promiseArray) {
    let successValue = [], count = 0
    return new myPromise((resolve, reject) => {
        
        const len = promiseArray.length
    	for(let i = 0; i < len; i++) {
        	promiseArray(i).then(v => {
            	count++
                successValue.push(v)
                if(count == len) {
                    resolve(successValue)
                }
        	}, e => {
            	reject(e)
        	})
    	}
    })
  
}

注意,这里不能说直接判断实例中是否有失败的情况,有的话直接执行后退出,没有就执行reoslve方法。因为有些promsie状态在执行all时还是pending,所以根本不会执行then方法,所以有时候该promise本应该是失败的,但最后all方法返回的确实成功的promise

Promise.race()

跟all差不多,但返回的promise状态由第一个promsie实例状态改变所决定,具体代码如下:

static race(promiseValue) {
    return new myPromise((resolve, reject) => {   
        const len = promiseArray.length
    	for(let i = 0; i < len; i++) {
            // 若有promsie实例状态已经确定了的话,直接执行resolve或者reject方法
        	promiseArray(i).then(v => {
                resolve(successValue)
                break
        	}, e => {
            	reject(e)
                break
        	})
    	}
    })
}

Promise.prototype.finally()

这不是一个静态方法,而是每个实例都会有的,下面是mdn的解释

**finally()** 方法返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。

这避免了同样的语句需要在 then() 和 catch() 中各写一次的情况。

也就是说,无论then方法执行哪一个回调,最后都会执行finally里面的回调函数,所以可以利用我们之前写的then方法,将两个回调都传入finally的回调,这样无论then返回什么样的promise,都会执行到finally里面的回调函数,具体代码如下:

finally(callback) {
    return this.then(callback, callback)
}

至此,断断续续写了将近一个星期的promise手写文档也就写好啦!!!虽然还有很多不足的地方,但以后有机会会继续修改的

【CATIA的二次开发38】对象Selection交互选择部分方法介绍01 在CATIA V5的VBA开发中,Selection对象是用户交互的核心组件,用于管理用户在图形区域或特征树中的选择操作。Selection 对象是 CATIA VBA 中的中央交互枢纽,充当用户界面与程序逻辑之间的桥梁。它代表当前在图形区域或特征树中被选中的元素集合,是自动化操作的基础。 阅读详情

相关推荐

在线迭代RLHF实战:从原理到实现,复现超越官方指令模型的工作流

大语言模型(LLM)的对齐技术是提升其与人类意图一致性的关键。其中,基于人类反馈的强化学习(RLHF)通过引入人类偏好信号,指导模型优化生成策略,是实现模型“有用”与“无害”的核心方法。其技术价值在于将抽象的“对齐”目标转化为可优化的奖励信号,从而显著提升模型在对话、推理等任务中的表现。然而,传统的离线RLHF存在数据分布偏移和奖励黑客等瓶颈。在线迭代RLHF通过构建“生成-评估-学习”的动态数据循环,让模型能够利用自身最新生成的数据进行持续优化,有效克服了上述问题,成为当前提升指令模型性能的前沿方向。本文

weixin_28725037的博客 368

手写Promise源码

纯手写Promise源码,如有遗漏场景或漏洞,请评论区指出,不胜感激!

5coder的大前端进阶之路-个人博客网站:blog.5coder.cn 362

带你学习Android中的ContentObserver

通过使用,开发者可以有效地监听系统设置的变化,例如屏幕亮度等。这种机制使得应用能够动态响应系统设置的更改,提升用户体验。在实现需要与系统设置交互的应用时,合理使用是非常重要的。

执剑人 1311

promise核心概念及手写promise(含源码)

实现以下结构的promise自定义封装。

weixin_56048772的博客 1124

winget安装提示:执行此命令时发生意外错误: InternetOpenUrl() failed. 0x80072efd

当我们使用Winget包管理器安装应用,提示错误:执行此命令时发生意外错误: InternetOpenUrl() failed. 0x80072efd 该怎么处理呢?请听我娓娓道来。

Linux I Tell U 8136

使用Dify打造视频生成工作流:从提示词到视频的完整指南

Dify作为开源LLM应用开发平台,通过可视化工作流编排实现从文本到视频的端到端生成,将创意周期从天级缩短至分钟级。核心流程包括提示词工程、视频API调用、存储分发和结果反馈。

牛奶夹心巧克力 3434

【源码】手写实现一个Promise

使用typescript实现一个promise

有趣愉悦的学习冒险 1103

Hypermesh二次开发实战:Tcl命令分类与常用函数详解(附避坑指南)

本文深入解析Hypermesh二次开发中Tcl命令的三大核心类别:界面命令、查询命令与修改命令。重点剖析了*createmark集合管理与hm_getvalue信息查询等关键函数的实战用法,并提供了避免Mark覆盖、生命周期管理等常见陷阱的实用指南,旨在帮助CAE工程师构建高效可靠的自动化前处理流程。

weixin_29233333的博客 240

Promise基本使用以及手写源码

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。所谓Promise,简单说就是一个容器,等Promise执行完,才会执行里面的东西,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。Promise有以下两个特点。

m0_74079648的博客 1736

C#中使用OpenCV的常用函数

c# opencv 常见操作

大黄鸭在发光的专栏 1079

物理学建模及仿真平台Chrono安装

Chrono是一个基于物理学的建模和仿真基础设施,它是在C++中实现的独立于平台的开源设计。一个projectchrono库可以嵌入到一个软件项目中,例如在可变形地形上运行的轮式和履带式车辆、机器人、机械电子系统、顺应性机构和流体固体相互作用现象。系统可以由刚性和柔性/顺应性部件组成,并带有约束、电机和接触;部件可以具有三维形状,以便进行碰撞检测。然而安装还是出现了一些问题,所以在此总结。已经装好visual studio。

Already8888的博客 6501

【手写Promise】史上最最最详细的手写Promise教程

转载自https://yq.aliyun.com/articles/613412 class Promise{ constructor(executor){ this.state = 'pending'; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; let resolve = va

Anles的博客 3769

56、Cortex - M33处理器浮点单元(FPU)的使用与优化

本文详细介绍了Cortex-M33处理器浮点单元(FPU)的使用与优化方法,涵盖单双精度浮点计算的选择、编译器命令行配置、ABI模式对比、特殊FPU模式设置(如Flush-to-Zero、Default NaN)、浮点异常处理机制以及FPU电源管理策略。结合代码示例和流程图,提供了在不同应用场景下的最佳实践建议,并总结了常见问题及解决方案,帮助开发者提升嵌入式系统中浮点运算的性能、精度与能效。

bread的博客 154

【手写 Promise 源码】目录 - Promise 知识点梳理

本篇,对 Promise 相关知识点进行梳理和拆分;作为Promise 专栏目录,随文章更新会持续完善,欢迎大家留言讨论和补充;

BraveWangDev 1051

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

从基础用法到源码实现:手写 Promise 的完整指南

1. 核心机制链式调用.then()始终返回新Promise,形成独立调用链,避免状态污染。异步优先级:通过微任务队列确保回调执行顺序优先于setTimeout等宏任务。错误冒泡:链式调用中未处理的错误会穿透到最近的.catch(),实现集中捕获。2. 实践挑战建议状态机实现(pendingfulfilledrejected回调队列存储(处理多次调用.then()返回值解析(支持普通值、Promise、thenable对象)循环引用检测(避免导致死锁)3. 巩固练习。

weixin_44840734的博客 1731

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

面试官:手写个 Promise 给我看看

本文详解如何手写 Promise,帮助前端开发者掌握异步编程核心原理。文章首先通过"煮开水→泡咖啡"的示例对比回调地狱和 Promise 链式调用的区别,说明 Promise 的核心价值。随后提供完整的 Promise 实现代码,包含状态管理、resolve/reject 逻辑和 then 方法实现。重点拆解了 Promise 的 5 个关键步骤:创建 Promise 时初始化状态、定义回调函数、执行异步操作;调用 then 方法时注册回调;以及异步操作完成后触发回调的完整流程。通过生活

前端圈边缘选手,擅长把 UI 稿 “翻译” 成代码,也擅长在 console.log 里写 “求救信号”。日常状态:要么在调像素级对齐,要么在查 “为什么这个样式只在我电脑上生效”。博客不搞高深理论,只唠实在干货~ 979

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Promise详细知识点(内含手写Promise)

promise相关知识和手写promise

ixxoic的博客 1370

方法 手写promise_手写源码系列二——Promise相关方法

欢迎关注微信公众号——“较真的前端”,里面有更多前端面试题和解答。手写Promise相关方法Promise是面试中经常遇到的,如果面试中面试官问你Promise.all()怎么用,那你面试的岗位差不多是高级前端开发的岗位,但如果让你手写一个Promise.all()那你面试的岗位应该就是资深/专家前端开发的岗位了上期回顾上期我们实现了函数的call()、bind()、apply()方法。Promi...

weixin_39611510的博客 127

手写Promise,一步步实现自己的Promise

手写promise,一步步实现自己的promise,从零到1实现promise

小时候可呆了的博客 2072

手写Promise的思路与源码,看这篇就够了

手写Promise思路与源码思路API的特性与源码构造函数thencatch验证一下Promise.resolvedPromise.rejected未完待续 思路 mdn上搜索Promise,了解类和api的定义: 定义了哪些属性,分别代表什么含义 api需要传什么参数,返回什么值,可能抛出什么异常 看官方给出的用例,猜想内部可能的实现 编写源码,用官方用例验证查看返回值是否一致 API的特性与源码 构造函数 promise有状态pending、rejected和resolved,所以应该有个变量来保

jianghao2016的博客 706

手写实现promise源码(附源码)

手写实现promise源码 源码下载 一、前言 需要掌握以下知识点 promise的基本使用 promise常见的API Js的事件循环机制 想复习或者学习promise的同学可以看看这篇文章 实现的主要功能 Promise.prototype.then Promise.prototype.catch Promise.resolve Promise.reject Promise.all Promise.race 二、代码实现 整体结构实现 (function(window){ const

GHkmmm的个人博客 595

手写 Promise 源码实现

关乎手写Promise,网上已经有好多相关资料,我也查阅过相关资料,但大多不够全,并且有些没那么易懂,所以自己想从头写个通俗易懂的Promise。 查看完整代码请戳:手写Promise

u011705725的博客 388
上一篇: leetcode122. 买卖股票的最佳时机||
下一篇: 重写宏任务与微任务!
Lin__hr
博客等级 码龄6年 5粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值