前言:
面试会遇到Promise,问你是怎么理解Promise的?
我的理解就是承诺!
编码代码,存在异步的地方都会遇到Promise! 搞了这么久,感觉理解不是很透
忽然想起一句话:学习法语糖的最好方法,是自己去实现ta,自己实现不了,就看比人怎么实现的
基本用法:
let promise = new Promise( function(resolve, reject) {
/* 异步操作 */ setTimeout(() => {
let number = Math.floor(Math.random() * 3)
if (number == 2) {
resolve(number);
} else {
reject('不是2')
}
}, 3000);
} )
promise.then(
(value) => {// then方法第一个参数onFulfilled,异步任务成功时调用
console.log(value);
},
(value) => {// then方法第二个参数onRejected,异步任务成功时调用
console.log(value);
}
);
根据上面的内容开始实现 Promise构造函数
function Promise(fn) {
//校验
if (!(this instanceof Promise))
throw new TypeError('Promise 前面必须加new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = 0; // _state有三个值 0代表PENDING(进行中)
//1代表FULFILLED (已成功)
//2代表REJECTED(已失败)
//3代表传入resolve的是Promise实例
this._value = undefined; //异步任务完成获取的值 reslove()或者reject()中传递的值
this._deferreds = []; //存放then函数传递的回调
doResolve(fn, this);
}
根据上面的例子可以看到Promise构造函数的参数是一个包含异步任务的函数
有了构造函数,接下来实现doResolve(fn, this),doResolve要做两件事,第一要执行我们传入的
包含异步任务的函数,同时传入resolve,reject参数 function(resolve, reject) {,可以看上线的例子
function doResolve(fn, self) {
var done = false;
fn(
function(value) { //第一个参数resolve,当异步成功完成调用
if (done) return;
done = true;
resolve(self, value);
},
function(reason) { //第二个参数reject,当异步完成失败调用
if (done) return;
done = true;
reject(self, reason);
}
);
}
其中利用闭包,保证传入的resolve,reject 只能调用一次,保持对self,Promise实例的引用
接下来实现resolve,reject,方法只是记录下_state的状态
function resolve(self, newValue) {
self._state = 1;
self._value = newValue;
finale(self);
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
实现finale,调用self._deferreds 存放then方法中传入的回调onFulfilled和onRejected
再没有调用then方法时,self._deferreds=[],当调用then 方法时判断self._state === 0是没有完成
就将then 方法的回调存入self._deferreds,如果已经完成,根据self._state为1或者2调用onFulfilled或者onRejected
function finale(self) {
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
function handle(self, deferred) {
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
setTimeout(function() {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
cb(self._value);
}, 0);
}
实现then方法,当调用then 方法时判断self._state === 0是没有完成
就将then 方法的回调存入self._deferreds,如果已经完成,根据self._state为1或者2调用onFulfilled或者onRejected
Promise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
onRejected = typeof onRejected === 'function' ? onRejected : null;
handle(this, {onFulfilled,onRejected});
}
基本的Promise就实现了,去掉很多细节
剩下的就是Promise的几个方法实现
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
Promise.resolve = function(value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {
reject(value);
});
};
Promise.race = function(values) {
return new Promise(function(resolve, reject) {
for (var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
这几个方法都很简单,复杂一点的是Promise.all;
Promise.all = function(arr) {
return new Promise(function(resolve, reject) {
if (!arr || typeof arr.length === 'undefined')
throw new TypeError('Promise.all accepts an array');
var args = Array.prototype.slice.call(arr);
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(
val,
function(val) {
res(i, val);
},
reject
);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
Promise.all传入的是一个Promise实例数组,通过计数方式当传入的Promise实例每完成一个--remaining,计数器减一,所有都完成了调用resolve触发then的回调
当你看完实现代码再结合阮一峰的讲解实例es6.ruanyifeng.com/#docs/promi…,应该可以更快的掌握
本文为了更好理解,省去了很多代码完整代码请查看promise-polyfill