promise实现
2019-04-19 本文已影响0人
CN__烟雨任平生
Promises/A+规范文档
Promises/A+规范文档中文翻译
Promise标准:
- 拥有一个then方法
- fulfill 成功时的操作,即resolve
- reject 失败时的操作
- padding 等待
一个简单的promise流程
function Promise(fn) {
var value = null
var callback = []
this.then = function(onFulfilled){
callbacks.push(onFulfilled)
}
function resolve(value){
callbacks.forEach(function(callback){
value = callback(value)
})
}
fn(resolve)
}
new Promise(
function(resolve){
setTimeout(()=>{
console.log(123)
return resolve(6)
},1000)
}
).then(
(v)=>{
console.log('1',v)
return v
}
)
// 一秒钟后
// 123
// 1 6
上述代码很简单,大家肯定都能看得懂。
- 将then方法挂载到callbacks队列
- 创建的promise实例传入的函数会被赋予resolve参数,resolve能启动callbacks队列,当异步函数执行完时,将结果给resolve,resolve就能带着这个结果启动callbacks,执行then函数。
不难发现,then是需要链式调用的,总所周知链式调用也很简单,只需要添加 return this
即可
修改如下
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;
};
这个时候我们删掉定时器,突然发现, 123
正常输出,但是1 6
并没有输出,为什么呢??这是因为,全程都是同步,当我们执行resolve的时候,then还没有挂载到队列上面。根据js执行机制,我们可以加一个setTimeout ,setTimeout是异步函数,属于宏任务,会放在任务最后。将resolve中执行回调的逻辑放在任务队列末尾,以保证resolve时,then方法已经全部挂载完毕即可。
function resolve(value) {
setTimeout(function() {
callbacks.forEach(function (callback) {
value = callback(value);
});
}, 0)
}
这是个时候可能我们又发现
new Promise(
function(resolve){
setTimeout(()=>{
console.log(123)
return resolve(6)
},1000)
}
).then(
(v)=>{
console.log('1',v)
return v
}
).then(
setTimeout((v)=>{
console.log('3', v)
},1000)
)
// 123
// 1 undefined
// 1 6
// Uncaught TypeError: callback is not a function
我们需要优化resolve方法
function resolve(value) {
setTimeout(()=>{
callbacks.forEach(function (callback) {
if (typeof callback === 'function') {
value = callback(value)
}
});
},0)
}
加入状态
pending
,fulfilled
,rejected
function Promise(fn) {
let value = null
let callbacks = []
let state = 'pending'
this.then = function (onFulfilled) {
if(state==='pending'){
callbacks.push(onFulfilled);
return this;
}
onFulfilled(value)
return this
};
function resolve(value) {
state = 'fulfilled'
setTimeout(()=>{
callbacks.forEach(function (callback) {
if (typeof callback === 'function') {
value = callback(value);
}
});
},0)
}
fn(resolve);
}
function Promise1(fn) {
var state = 'pending'
var value = null
var callbacks = []
this.then = function (onFulfilled, onRejected) {
return new Promise1(function (resolve, reject) {
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
})
})
}
function handle(callback){
console.log(state)
if(state === 'pending'){
callbacks.push(callback)
return
}
console.log(state)
var cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected
var ret
if(cb === null){
cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected
cb(value)
return
}
try{
ret = cb(value)
console.log('ret',ret)
callback.resolve(ret)
}catch(e){
callback.reject(e)
}
}
function resolve(newValue){
if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){
console.log('function')
var then = newValue.then
if(typeof then ==='function'){
then.call(newValue,resolve,reject)
return
}
}
console.log('nofunction')
state = 'fulfilled'
value = newValue
execute()
}
function reject(reason){
state = 'rejected'
value = reason
execute()
}
function execute(){
setTimeout(function(){
callbacks.forEach(function(callback){
handle(callback)
})
},0)
}
fn(resolve,reject)
}