We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
原生Promise,拥有基本的then方法,并且在new一个Promise的时候传入一个函数,该函数的参数有resolve和reject(暂时不讨论),我们知道,在定义一个Promise的时候,js执行栈会先执行promise里面传入的这个函数,然后把resolve传给他,并注册一些then函数,再最终执行resolve的时候再把then注册的回调函数依次执行,类似于观察者模式,这也算为什么考察事件循环时,
new Promise((res, rej) => { console.log(111); // 这里的打印正是在当前栈同步执行了这个回调函数。 setTimeout(() => console.log(222), 2000); }) console.log(333) 会打印出 // 111 333 2秒后打印222
根据上面的分析,我们写一个简单的能实现then功能的promise
function MyPromise(fn) { const callbacks = []; // 存储then注册的回调函数 let value = null; // 当前最新resolve的值 this.then = function(callback) { callbacks.push(callback); // 注册回调 return this; // 返回promise,用于链式 } function resolve(newValue) { value = newValue; callbacks.forEach(function (callback) { callback(value); // 依次执行回调 }) } fn(resolve); } const p1 = new MyPromise(resolve => setTimeout(() => resolve(111), 1000)).then(data => console.log(data)); // 一秒后打印111
但是我们发现当promise传入的是同步方法的时候,即立即resolve的时候,then来不及注册回调,这是由于事件循环导致的,同步方法顺序执行,因此需要将resolve函数的执行回调放到当前任务队列的最后,保证then注册完了所有回调函数
// 改造resolve function resolve(newValue) { value = newValue; setTimeout(() => { callbacks.forEach(function (callback) { callback(value); }) }, 0); } const p2 = new MyPromise(resolve => resolve(111)).then(data => console.log(data)); // 立即打印111 setTimeout(() => p2.then(data => console.log(data)), 0) // 打印不出data,是因为resolve已经结束了,在异步操作成功之前注册的回调都会执行,但是在Promise异步操作成功这之后调用的then注册的回调就再也不会执行了
解决上述问题,可以在promise内部加入状态,就是pending、fulfilled、rejected(先不讲),如果处于pending状态,可以then注册回调函数,如果已经resolve成功,状态改为fulfilled,此时再再then里面注册的回调函数,直接使用最新的当前值value
function MyPromise(fn) { const callbacks = []; let value = null; let state = 'pending'; this.then = function(callback) { if (state === 'pending') { callbacks.push(callback); } else if (state === 'fulfilled') { callback(value); } return this; } function resolve(newValue) { state = 'fulfilled'; value = newValue; setTimeout(() => { callbacks.forEach(function (callback) { callback(value); }) }, 0); } fn(resolve); } // 都测试一下 const p1 = new MyPromise(resolve => setTimeout(() => resolve(111), 1000)).then(data => console.log(data)); setTimeout(() => p1.then(data => console.log(data)), 0) // 1秒后正常打印出111 111 const p2 = new MyPromise(resolve => resolve(111)).then(data => console.log(data)); setTimeout(() => p2.then(data => console.log(data)), 0) // 正常打印出111 111
上述解决了异步和同步操作的问题,以及状态机制。 那么我们知道原生的promise的then里面可以返回一个promise,实现多个promise的链式调用,链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise(后邻promise)。那么我们如何衔接当前promise和后邻promise呢?由于目前的设计then里面都是普通回调函数,执行后返回的值直接调用resolve赋值给value,那么如果then注册了一个promise,就会在这个promise里面执行resolve,需要等待这个promise的异步操作,并将新的promise的值resolve传递给第一个promise的value。
promise1().then(promise2)
promise1的resolve执行后,then回调函数执行,这个then函数需要负责把回调函数的值提到当层,便于给后面的回调函数使用,因此如果then传入的是一个promise2,需要想办法把promise2里层的resolve值拿到新层promise,那么最简单的办法就是在then里面返回一个新层promise,用新层的resolve,来截获promise2的resolve值。才能传递给后面的promise3使用,形象的来说就是你多个promise链式调用,需要每次使用一个新的promise来进行衔接。才能达到数据在各个promise之间游走。 让我们看看如何改造:
function MyPromise(fn) { const callbacks = []; let value = null; let state = 'pending'; this.then = function(callback) { return new MyPromise(resolve => { if (state === 'pending') { callbacks.push({ callback, resolve }); return; } else if (state === 'fulfilled') { resolve(callback(value)); return; } }) } function resolve(newValue) { if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { var then = newValue.then; if (typeof then === 'function') { then.call(newValue, resolve); return; } } state = 'fulfilled'; value = newValue; setTimeout(() => { callbacks.forEach(function (callback) { callback.resolve(callback.callback ? callback.callback(value) : value); }) }, 0); } fn(resolve); } const p3 = new MyPromise(resolve => setTimeout(() => resolve(111), 1000)).then(data => { console.log(data) return new MyPromise(resolve => setTimeout(() => resolve(222), 1000)) }) .then().then(data => { console.log(data) return new MyPromise(resolve => resolve(333)).then(data1 => { console.log(data1) }) }); // 正常打印 111 222 333
总的来说前面几步都比较好理解,关于如何注册回调函数,如何在resolve的时候执行注册的回调函数,promise里面的then函数仅仅是注册了后续需要执行的代码,真正的执行是在resolve方法里面执行的。再根据原生promise的一些特性,逐个进行分析,实现一些功能。boom!!!!
The text was updated successfully, but these errors were encountered:
No branches or pull requests
定义MyPromise
原生Promise,拥有基本的then方法,并且在new一个Promise的时候传入一个函数,该函数的参数有resolve和reject(暂时不讨论),我们知道,在定义一个Promise的时候,js执行栈会先执行promise里面传入的这个函数,然后把resolve传给他,并注册一些then函数,再最终执行resolve的时候再把then注册的回调函数依次执行,类似于观察者模式,这也算为什么考察事件循环时,
根据上面的分析,我们写一个简单的能实现then功能的promise
加入延迟机制
但是我们发现当promise传入的是同步方法的时候,即立即resolve的时候,then来不及注册回调,这是由于事件循环导致的,同步方法顺序执行,因此需要将resolve函数的执行回调放到当前任务队列的最后,保证then注册完了所有回调函数
加入状态
解决上述问题,可以在promise内部加入状态,就是pending、fulfilled、rejected(先不讲),如果处于pending状态,可以then注册回调函数,如果已经resolve成功,状态改为fulfilled,此时再再then里面注册的回调函数,直接使用最新的当前值value
上述解决了异步和同步操作的问题,以及状态机制。
那么我们知道原生的promise的then里面可以返回一个promise,实现多个promise的链式调用,链式Promise是指在当前promise达到fulfilled状态后,即开始进行下一个promise(后邻promise)。那么我们如何衔接当前promise和后邻promise呢?由于目前的设计then里面都是普通回调函数,执行后返回的值直接调用resolve赋值给value,那么如果then注册了一个promise,就会在这个promise里面执行resolve,需要等待这个promise的异步操作,并将新的promise的值resolve传递给第一个promise的value。
promise1的resolve执行后,then回调函数执行,这个then函数需要负责把回调函数的值提到当层,便于给后面的回调函数使用,因此如果then传入的是一个promise2,需要想办法把promise2里层的resolve值拿到新层promise,那么最简单的办法就是在then里面返回一个新层promise,用新层的resolve,来截获promise2的resolve值。才能传递给后面的promise3使用,形象的来说就是你多个promise链式调用,需要每次使用一个新的promise来进行衔接。才能达到数据在各个promise之间游走。
让我们看看如何改造:
总结
总的来说前面几步都比较好理解,关于如何注册回调函数,如何在resolve的时候执行注册的回调函数,promise里面的then函数仅仅是注册了后续需要执行的代码,真正的执行是在resolve方法里面执行的。再根据原生promise的一些特性,逐个进行分析,实现一些功能。boom!!!!
The text was updated successfully, but these errors were encountered: