近来研讨了一下promise的完成,这篇文章运用了十几行代码完成了一个简朴的promise;以便协助读者对promise’有更深的相识。本篇文章完成的promise,遵照范例是 Promises/A+。
浏览本篇文章时,已假定你会promise的基础运用和一些简朴的es6语法;假如你还没控制promise的基础运用,请进修终了后再来。引荐能够看《promise迷你书》、《你不知道的js》及阮一峰先生的《ECMAScript 6 入门》。
promise的中心完成
起首,我们看一下一个promise的基础用法:
var p = new MyPromise((resolve) => {
setTimeout(() => {
resolve(20)
}, 300)
})
p.then( (msg) => console.log(msg) );
MyPromise是一个组织函数,这个组织函数会被通报一个函数;函数中有两个参数,是两个函数resolve,reject。别的一个promise有三种状况PENDING、RESOLVED、REJECTED。所以我们有以下的代码:
const PENDING = 0;
const RESOLVED = 1;
const REJECTED = 2;
function MyPromise(func){
let state = PENDING;
let value = null;
function resolve(newValue){
value = newValue;
state = RESOLVED;
}
function reject(err){
value = err;
state = REJECTED;
}
func(resolve, reject);
}
然后我们完成then函数,每次then函数的实行会返回一个新的promise。
this.then = function(onFullFill, onReject){
return new MyPromise((resolve, reject) => {
})
}
通报给then函数onFullFill函数返回值,会通报给第二个then中onFullFill中。即要能如许运用p.then( (msg) => msg ).then( data => console.log(data) );
这行代码现实是什么呢?让我们变更一下上面的代码:
p
.then( function fn1(msg){
return msg;
})
.then( function fn2(data){
console.log(data);
})
//以上代码的本质
fn2(fn1(msg))
我们要在then函数内里怎样实行resolve函数呢?起首resolve函数是必需实行的,因为它要转变p.then()天生的promise的状况;其次,resolve这个函数还要能接遭到onFullFill实行的值;以便通报给下一个回调函数。你能够想到了这类计划:
const PENDING = 0;
const RESOLVED = 1;
const REJECTED = 2;
function MyPromise(func){
let state = PENDING;
let value = null;
function resolve(newValue){
value = newValue;
state = RESOLVED;
}
function reject(err){
value = err;
state = REJECTED;
}
this.then = function(onFullFill, onReject){
return new MyPromise((resolve, reject) => {
resolve(onFullFill(value));
})
}
func(resolve, reject);
}
var p = new MyPromise((resolve) => {
setTimeout(() => {
resolve(20)
}, 300)
})
p.then( (msg) => msg ).then( data => console.log(data) );
然则当你把以上代码拼集在一起,实行;打印出来的是null。why?
因为setTimeout(fn, 300)
这行代码是异步实行的,而当promise中的state!==RESOLVED时,这行代码resolve(onFullFill(value))
;不应当实行。所以我们有了以下的优化:
function MyPromise(func){
let state = PENDING;
let value = null;
let handlers = [];
function resolve(newValue){
value = newValue;
state = RESOLVED;
handlers.forEach( handler => handle(handler));
}
function reject(err){
value = err;
state = REJECTED;
}
function handle(handler){
if(state === PENDING){
handlers.push(handler);
return;
}
handler.resolve(handler.onFullFill(value));
}
this.then = function(onFullFill, onReject){
return new MyPromise((resolve, reject) => {
handle({
resolve: resolve,
onFullFill: onFullFill
})
})
}
func(resolve, reject);
}
如许在then函数里和resolve函数里我们都邑实行handle函数,但只要在resolve函数实行后才会实行handler.resolve(handler.onFullFill(value))
。
如今另有一个题目,假如Promise中封装的不是异步操纵,而是同步操纵;那末resolve函数就会比then函数更先实行。
var p = new MyPromise((resolve, reject) => {
resolve('同步操纵')
})
p.then(console.log)
所以我们实行resolve中的回调的时刻,应当异步实行:
function resolve(newValue){
value = newValue;
state = RESOLVED;
setTimeout( () => {
handlers.forEach( handler => handle(handler));
}, 0)
}
同时,因为then函数中能够吸收一个promise;我们需要对这类状况举行处置惩罚:
function resolve = (newValue) => {
if(newValue && (typeof newValue === 'object' || typeonewValue === 'function') {
let then = newValue.then
if(typeof then === 'function'){
return then.call(newValue, resolve)
}
state = FULFILLED;
value = newValue;
setTimeout(() => {
handlers.forEach(handler => {
handle(handler)
})
}, 0)
}
至此,我们已完成了一个基础promise的完成。