//Promise版本的Ajax
const getJSON = function(url) { const promise =new Promise(function(resolve, reject) { const handler = function() { if(this.readyState!==4) { return; } if(this.status===200) { resolve(this.responseText); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange=handler; client.responseType="json"; client.setRequestHeader("Accept", "application/json"); client.send(); }); return promise; };
getJSON("./demo.json").then(function(json) {
console.log("Contents: "+ json);
}).catch(function(err){
console.log('出錯了',err);
});
//Promise實現 (function(window,undefined){ // resolve 和 reject 最終都會調用該函數 var final = function(status,value){ var promise = this, fn, st; if(promise._status !== 'PENDING') return; // 因此的執行都是異步調用,保證then是先執行的 setTimeout(function(){ promise._status = status; st = promise._status === 'FULFILLED' queue = promise[st ? '_resolves' : '_rejects']; while(fn = queue.shift()) { value = fn.call(promise, value) || value; } promise[st ? '_value' : '_reason'] = value; promise['_resolves'] = promise['_rejects'] = undefined; }); } //參數是一個函數,內部提供兩個函數做爲該函數的參數,分別是resolve 和 reject var Promise = function(resolver){ if (!(typeof resolver === 'function' )) throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); //若是不是promise實例,就new一個 if(!(this instanceof Promise)) return new Promise(resolver); var promise = this; promise._value; promise._reason; promise._status = 'PENDING'; //存儲狀態 promise._resolves = []; promise._rejects = []; // var resolve = function(value) { //因爲apply參數是arguments final.apply(promise,['FULFILLED'].concat([value])); } var reject = function(reason){ final.apply(promise,['REJECTED'].concat([reason])); } resolver(resolve,reject); } Promise.prototype.then = function(onFulfilled,onRejected){ var promise = this; // 每次返回一個promise,保證是可thenable的 return new Promise(function(resolve,reject){ function handle(value) { // 這一步很關鍵,只有這樣才能夠將值傳遞給下一個resolve var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value; //判斷是否是promise 對象 if (ret && typeof ret ['then'] == 'function') { ret.then(function(value) { resolve(value); }, function(reason) { reject(reason); }); } else { resolve(ret); } } function errback(reason){ reason = typeof onRejected === 'function' && onRejected(reason) || reason; reject(reason); } if(promise._status === 'PENDING'){ promise._resolves.push(handle); promise._rejects.push(errback); }else if(promise._status === 'FULFILLED'){ // 狀態改變後的then操做,馬上執行 callback(promise._value); }else if(promise._status === 'REJECTED'){ errback(promise._reason); } }); } Promise.prototype.catch = function(onRejected){ return this.then(undefined, onRejected) } Promise.prototype.delay = function(ms,value){ return this.then(function(ori){ return Promise.delay(ms,value || ori); }) } Promise.delay = function(ms,value){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve(value); console.log('1'); },ms); }) } Promise.resolve = function(arg){ return new Promise(function(resolve,reject){ resolve(arg); }) } Promise.reject = function(arg){ return Promise(function(resolve,reject){ reject(arg); }) } Promise.all = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to all.'); } return Promise(function(resolve,reject){ var i = 0, result = [], len = promises.length, count = len //這裏與race中的函數相比,多了一層嵌套,要傳入index function resolver(index) { return function(value) { resolveAll(index, value); }; } function rejecter(reason){ reject(reason); } function resolveAll(index,value){ result[index] = value; if( --count == 0){ resolve(result) } } for (; i < len; i++) { promises[i].then(resolver(i),rejecter); } }); } Promise.race = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to race.'); } return Promise(function(resolve,reject){ var i = 0, len = promises.length; function resolver(value) { resolve(value); } function rejecter(reason){ reject(reason); } for (; i < len; i++) { promises[i].then(resolver,rejecter); } }); } window.Promise = Promise; })(window);