ES6 原生提供了 Promise 對象,大大簡化了 callback 的代碼維護難度。使用promise對象以後能夠使用一種鏈式調用的方式來組織代碼;讓代碼更加的直觀。ajax
若是想在老瀏覽器中使用 Promise,須要使用第三方庫。實際實現遠離並不複雜,僅須要十幾行代碼,就能實現相似的效果(實際仍是有點區別的)。promise
// 簡單的實現 Promise 的函數 // 原文地址:http://www.miaoqiyuan.cn/p/promise var PromiseDemo = function(fun, _status_code){ this._status_code = _status_code || 'status'; //執行 this.run = function(){ this._result = fun.call(this, fun); //若是執行函數會 同步 返回結果,則調用callback。 if( !! this._result ){ return this.callback(); }; }; //回調函數,若是不是當即返回結果,須要手動調用 this.callback = function(_result){ //異部調用時,傳入執行結果 if( !!_result ){ this._result = _result; } //如過狀態不是 object this._result = this._result || {}; //若是沒有指定 【返回狀態】 值,若是沒有,則使用 status this._status = this._result[this._status_code] || 'fail'; /* 若是 【返回狀態】 已經定義了 回調函數,調用本狀態回調函數 若是 【返回狀態】 沒有定義,則調用 _default 函數 若是 【返回狀態】 沒有定義,而且沒有調用 _default 函數,拋出異常 */ this._callback = this[this._status] || this._default || function(){ throw new Error("Undefined " + this._status); }; return this._callback.call(this); }; //then判斷 this.then = function(_status, callback){ if( typeof _status == "function" ){ //沒有指定狀態 callback = _status; if( !('success' in this) ){ //沒有 success,則將 callback 設置爲 success 狀態的回調函數 _status = 'success'; }else if( !('fail' in this) ){ //沒有 fail,則將 callback 設置爲 fail 狀態的回調函數 _status = 'fail'; }else{ // 若是 success 和 fail 已經設置,不管調用多少次,都是 默認狀態 的回調函數 _status = '_default'; }; }; //設置 【返回狀態】 的回調函數 this[_status] = callback; //鏈式操做 return this; }; //鏈式操做 return this; }
就這麼幾行代碼,就實現了簡單的 Promise。爲了方便測試,寫成函數
var PromiseTest = function(fun, _status_code, _default){ if( typeof _status_code == "function" ){ _default = _status_code; _status_code = undefined; } var pTest = new PromiseDemo(fun, _status_code); pTest.then(function(){ console.log("Success!"); console.log(this._result); }); pTest.then(function(){ console.log("Fail!"); console.log(this._result); }); if( typeof _default == "function"){ pTest.then(_default); }; return pTest; }
下面的代碼用於測試效果: 返回成功狀態
PromiseTest(function(){ return { status: 'success'}; }).run(); /* Success! Object {status: "success"} */
返回失敗狀態
PromiseTest(function(){ return { status: 'fail'}; }).run(); /* Fail! Object {status: "fail"} */
返回其餘狀態,沒有定義,拋出異常
PromiseTest(function(){ return { status: 'other'}; }).run(); /* Uncaught Error: Undefined other(…) */
修改 【返回狀態】 參數,返回成功狀態
PromiseTest(function(){ return { status: 'other', code : 'success'}; }, "code").run(); /* Success! Object {status: "other", code: "success"} */
增長默認值函數,全部未定義的狀態,都是用此回調函數
PromiseTest(function(){ return { status: 'other'}; }, function(){ console.log("Other"); }).run(); /* Other */
自定義狀態值,返回 nicai 狀態
PromiseTest(function(){ return { status: 'nicai'}; }).then('wocai', function(){ console.log("Wocai"); }).then('nicai', function(){ console.log("Nicai"); }).run(); /* Nicai */
同步調用有返回值
PromiseTest(function(){ return { status: 'nicai', value : "abc"}; }).then('nicai', function(){ console.log("Nicai"); return this._result.value; }).run() == 'abc'; /* Nicai true */
異部調用測試:setTimeout
PromiseTest(function(){ setTimeout( (function(){ this.callback({ status : 'success' }); }).bind(this), //必須bind,不然函數內部的 this == window 1000); }).run(); /* Success! Object {status: "success"} */
異部調用測試:Ajax
PromiseTest(function(){ $.ajax({ type : "POST", url : "/services/PinYin", data : {input:'測試'}, success : (function(result){ this.callback({ status : 'success', result : result }); }).bind(this), //經過 bind 改變 this 的指向 error : (function(){ this.callback(); }).bind(this) }); }).run(); //成功 /* Success! Object {status: "success", result: "Ceshi"} */ //失敗 /* Fail! Object {} */
異部調用測試:若是須要用 this 訪問 jQuery 的 ajax 對象
PromiseTest(function(){ var me = this; //在本函數內,用能夠 me 指向 this(PromiseDemo的實例); $.ajax({ type : "POST", url : "/services/PinYin", data : {input:'測試'}, success : (function(result){ me.callback({ status : 'success', result : result }); }), error : (function(){ me.callback(); }) }); }).run();