Promise定义
A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.
Promise实现
状态机
Promise实际是一个状态机,从后面需要用到的状态开始实现Promise.
var PENDING = 0;var FULFILLED = 1;var REJECTED = 2;function Promise() { //存储三种状态:PENDING, FULFILLED, REJECTED.初始状态是PENDING var state = PENDING; //存储结果或者错误,一旦FULFILLED 或者 REJECTED var value = null; //存储sucess和failure处理函数,绑定在.then和.done var handlers = [];}
下一步,添加两种过渡状态fulfilling和rejecting:
var PENDING = 0;var FULFILLED = 1;var REJECTED = 2;function Promise() { // store state which can be PENDING, FULFILLED or REJECTED var state = PENDING; // store value once FULFILLED or REJECTED var value = null; // store sucess & failure handlers var handlers = []; function fulfill(result) { state = FULFILLED; value = result; } function reject(error) { state = REJECTED; value = error; }}
上面是两种初级过渡,下面是更高级的过渡,叫做resolve:
var PENDING = 0;var FULFILLED = 1;var REJECTED = 2;function Promise() { // store state which can be PENDING, FULFILLED or REJECTED var state = PENDING; // store value once FULFILLED or REJECTED var value = null; // store sucess & failure handlers var handlers = []; function fulfill(result) { state = FULFILLED; value = result; } function reject(error) { state = REJECTED; value = error; } function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } }}/** * Check if a value is a Promise and, if it is, * return the `then` method of that promise. * * @param {Promise|Any} value * @return {Function|Null} */function getThen(value) { var t = typeof value; if (value && (t === 'object' || t === 'function')) { var then = value.then; if (typeof then === 'function') { return then; } } return null;}/** * Take a potentially misbehaving resolver function and make sure * onFulfilled and onRejected are only called once. * * Makes no guarantees about asynchrony. * * @param {Function} fn A resolver function that may not be trusted * @param {Function} onFulfilled * @param {Function} onRejected */function doResolve(fn, onFulfilled, onRejected) { var done = false; try { fn(function (value) { if (done) return done = true onFulfilled(value) }, function (reason) { if (done) return done = true onRejected(reason) }) } catch (ex) { if (done) return done = true onRejected(ex) }}
以上代码的简单实现看参考:
Promise状态
Promise对象有以下几种状态:
pending: 初始状态, 非 fulfilled 或 rejected.
fulfilled: 成功的操作.(如果promise.then(f),立刻调用f)
rejected: 失败的操作.(如果promise.then(undefined, r),立刻调用r)
如果一个promise对象处在fulfilled或rejected状态而不是pending状态,那么它也可以被称为settled状态。你可能也会听到一个术语resolved,它表示promise对象处于settled状态,或者promise对象被锁定在了调用链中。settled不是一种状态,而是一种语法上的便利。
Promise方法
Promise.resolve(value/promise/thenable)
Promise.resolve(value)方法返回一个以给定值resolve掉的Promise对象。但如果这个值是thenable的(就是说带有then方法),返回的promise会“追随”这个thenable的对象,接收它的最终状态(指resolved/rejected/pendding/settled);否则这个被返回的promise对象会以这个值被fulfilled。
//Examplevar p = Promise.resolve([1,2,3]);p.then(function(v) { console.log(v[0]); // 1});
//PolyfillPromise.resolve = function (value) { return new Promise(function (resolve) { resolve(value); });};
Promise.reject(reason)
Promise.reject(reason)方法返回一个用reason拒绝的Promise.
//ExamplePromise.reject(new Error("fail")).then(function(error) { // 未被调用}, function(error) { console.log(error); // 堆栈跟踪});
//PolyfillPromise.reject = function (value) { return new Promise(function (resolve, reject) { reject(value); });};
Promise.race(iterable)
Promise.race(iterable)方法返回一个promise,这个promise在iterable中的任意一个promise被解决或拒绝后,立刻以相同的解决值被解决或以相同的拒绝原因被拒绝。
//Examplevar p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "一"); });var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "二"); });Promise.race([p1, p2]).then(function(value) { console.log(value); // "二" // 两个都解决,但p2更快});
//PolyfillPromise.race = function (values) { // TODO: this polyfill only supports array-likes // it should support all iterables return new Promise(function (resolve, reject) { values.forEach(function(value){ Promise.resolve(value).then(resolve, reject); }); });};
Promise.all(iterable)
Promise.all(iterable) 方法返回一个promise,该promise会在iterable参数内的所有promise都被解决后被解决。
//Examplevar p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 1000, "one"); }); var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 2000, "two"); });var p3 = new Promise(function(resolve, reject) { setTimeout(resolve, 3000, "three");});var p4 = new Promise(function(resolve, reject) { setTimeout(resolve, 4000, "four");});var p5 = new Promise(function(resolve, reject) { reject("reject");});Promise.all([p1, p2, p3, p4, p5]).then(function(value) { console.log(value);}, function(reason) { console.log(reason) //"reject"});
//PolyfillPromise.all = function (arr) { // TODO: this polyfill only supports array-likes // it should support all iterables var args = Array.prototype.slice.call(arr); return new Promise(function (resolve, reject) { if (args.length === 0) return resolve([]); var remaining = args.length; function res(i, val) { if (val && (typeof val === 'object' || typeof val === 'function')) { var then = val.then; if (typeof then === 'function') { var p = new Promise(then.bind(val)); p.then(function (val) { res(i, val); }, reject); return; } } args[i] = val; if (--remaining === 0) { resolve(args); } } for (var i = 0; i < args.length; i++) { res(i, args[i]); } });};
Promise.prototype.then(onFulfilled, onRejected)
Promise实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。
//Examplevar p1 = new Promise(function(resolve, reject) { resolve("Success!"); // or // reject ("Error!");});p1.then(function(value) { console.log(value); // Success!}, function(reason) { console.log(reason); // Error!});
Promise.prototype.catch(onRejected)
等同于调用Promise.prototype.then(undefined, onRejected)
//Examplevar p1 = new Promise(function(resolve, reject) { resolve("Success");});p1.then(function(value) { console.log(value); // "Success!" throw "oh, no!";}).catch(function(e) { console.log(e); // "oh, no!"});
//PolyfillPromise.prototype['catch'] = function (onRejected) { return this.then(null, onRejected);};