摘要:實現是中的一種異步編程實現方式,中異步編程主要是指瀏覽器事件處理,等,通過傳入回調函數來實現控制反轉。對象符合編程規范,目的是為異步編程提供統一接口,它最大的優點就是避免了回調金字塔。
promise實現
Promise是Javascript中的一種異步編程實現方式,js中異步編程主要是指瀏覽器DOM事件處理,setTimeout/setInterval,ajax等,通過傳入回調函數來實現控制反轉。Promsie對象符合CommonJS編程規范,目的是為異步編程提供統一接口,它最大的優點就是避免了回調金字塔。
假設要實現一個用戶展示的任務,任務分為三步:
獲取用戶信息
獲取用戶圖片
彈窗提示
一般之前使用方式為:
之前已經對getUserInfo()和getUserImage(),showTip()方法進行了定義
getUserInfo(id, function(info){ getUserImage(info.img, function(){ showTip(); }) })
如果回調函數不止3個,那將會是一個非常長的回調,換成Promise實現:
//getUserInfo返回promise getUserInfo(id) .then(getUserImage) .then(showTip) .catch(function(e){ console.log(e); });
簡單的講,Promsie的思想就是每一個異步任務返回一個promise對象,該對象有一個then方法,允許指定回調函數。這里getUserInfo的回調函數就是getUserImage。
getUserInfo函數要進行如下改寫(這里用jQuery的Deferred()實現)
function getUserInfo(id){ var dfd = $.Deferred(); setTimeout(function(){ //獲取用戶信息 dfd.resolve(); }, 500); return dfd.promise; }
這樣一種寫法回調函數就成了鏈式寫法,程序的流程非常清楚,可以實現多個回調。
先在ES6出來之后,許多瀏覽器已經支持Promise方法,
promise有三種狀態:
pending:初始狀態
fulfilled:成功操作
rejected:失敗操作
開始的時候promise是pending狀態,fulfill之后就會執行回調then的回調函數,如果是reject就會調用catch進行異常處理,Promise.prototype.then() 和 Promise.prototype.catch() 兩種方法狀態都會返回一個promise對象,用于后續鏈式調用。
"use strict"; var promiseCount = 0; function testPromise(){ var thisPromiseCount = promiseCount++; var log = document.getElementById("log"); log.insertAdjacentHTML("beforeend", thisPromiseCount + ") 開始 (異步調用開始)
"); //新建一個promsie對象 var p1 = new Promise(function(resolve, reject){ log.insertAdjacentHTML("beforeend", thisPromiseCount + ") Promise 開始執行 (異步調用開始)
"); window.setTimeout(function(){ resolve(thisPromiseCount); }, 2000) }); //定義promise執行fulfilled執行的then()回調函數以及執行reject后的catch回調函數 p1.then( function(val) { log.insertAdjacentHTML("beforeend", val + ") Promise fulfilled (異步代碼中斷)
"); }) .catch( function(reason) { console.log("Handle rejected promise ("+reason+") here."); }); log.insertAdjacentHTML("beforeend", thisPromiseCount + ") 建立promise"); }if ("Promise" in window) { var btn = document.getElementById("btn"); btn.addEventListener("click",testPromise); } else { log = document.getElementById("log"); log.innerHTML = "瀏覽器不支持promise接口"; } }
單擊按鈕后,首先執行promise
實現XMLHttpRequest獲取數據3秒之后resolve調用then()方法
使用ajax異步加載圖片
function imgLoad(url) { //返回promsie對象 return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "blob"; xhr.onload = function() { if (xhr.status === 200) { resolve(xhr.response); } else { reject(Error("圖像加載失敗; 錯誤原因:" + xhr.statusText)); } }; xhr.onerror = function() { reject(Error("加載錯誤.")); }; xhr.send(); }); } var body = document.querySelector("body"); var myImage = new Image(); var url = "http://7qnb7a.com1.z0.glb.clouddn.com/6608717992840918931.jpg"; imgLoad(url).then(function(response) { var imageURL = window.URL.createObjectURL(response); myImage.src = imageURL; body.appendChild(myImage); }, function(Error) { console.log(Error); });構建一個簡單的promise模式框架
首先需要建立一個對象來存儲promise
Promise = function(){ this.queue = []; this.value = null; this.status = "pending"; };
定義獲取隊列,設定狀態和獲取狀態原型方法
Promsie.prototype.getQueue = function(){ return this.queue; }; Promise.prototype.getStatus = function(){ return this.status; }; Promise.prototype.setStatus = function(s, value){ if(s === "fulfilled" || s === "rejected"){ this.status = s; this.value = value || null; this.queue = []; var freezeObject = Object.freeze || function(){}; freezeObject(this); }else{ throw new Error({message:"doesn"t support status: "+s}); } };
定義then方法,接受兩個參數用于完成和拒絕任務操作。
Promise.prototype.then = function(onFulfilled, onRejected){ var handler = { "fulfilled": onFulfilled, "rejected": onRejected }; handler.deferred = new Deferred(); if(!this.isPending()){ utils.procedure(this.status, handler, this.value); }else{ this.queue.push(handler); } return handler.deferred.promise; };
定義三個不同狀態函數
Promise.prototype.isFulfilled = function(){ return this.status === "fulfilled"; }; Promise.prototype.isRejected = function(){ return this.status === "rejected"; }; Promise.prototype.isPending = function(){ return this.status === "pending"; };
工具處理函數
var utils = (function(){ var makeSignaler = function(deferred, type){ return function(result){ transition(deferred, type, result); } }; var procedure = function(type, handler, result){ var func = handler[type]; var def = handler.deferred; if(func){ try{ var newResult = func(result); if(newResult && typeof newResult.then === "function"){ newResult.then(makeSignaler(def, "fulfilled"), makeSignaler(def, "rejected")); }else{transition(def, type, newResult);} }catch(err){transition(def, "rejected", err);} }else{transition(def, type, result);} }; var transition = function(deferred, type, result){ if(type === "fulfilled"){ deferred.resolve(result); }else if(type === "rejected"){ deferred.reject(result); }else if(type !== "pending"){ throw new Error({"messgae":"doesn,t support type:"+type}); } }; return { "procedure": procedure } })();
定義延遲函數
Deferred = function() { this.promise = new Promise(); }; Deferred.prototype.resolve = function(result) { if (!this.promise.isPending()) { return; } var queue = this.promise.getQueue(); for (var i = 0, len = queue.length; i < len; i++) { utils.procedure("fulfilled", queue[i], result); } this.promise.setStatus("fulfilled", result); }; Deferred.prototype.reject = function(err) { if (!this.promise.isPending()) { return; } var queue = this.promise.getQueue(); for (var i = 0, len = queue.length; i < len; i++) { utils.procedure("rejected", queue[i], err); } this.promise.setStatus("rejected", err); }
有很多實現了promises的庫供開發者可用。 像jQuery的 Deferred, 微軟的 WinJS.Promise, when.js, q, 和dojo.Deferred.
關于jQuery的Deferred可以參考jQuery的deferred對象詳解
Promise MDN
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79070.html
摘要:標準已于年月份正式定稿了,并廣泛支持最新的特性異步函數。為了領會,我們需要回到普通回調函數中進一步學習。從此編寫回調函數不再那么痛苦。回調是一個函數,可以將結果傳遞給函數并在該函數內進行調用,以便作為事件的響應。 ES2017標準已于2017年6月份正式定稿了,并廣泛支持最新的特性:異步函數。如果你曾經被異步 JavaScript 的邏輯困擾,這么新函數正是為你設計的。 異步函數或多或...
摘要:斷言斷言是什么模塊提供了一組簡單的斷言測試,可用于測試不變量。環境是他們不必設置大量配置的環境,而是開發人員可以編寫代碼并從測試中獲得即時反饋的地方。每當測試時,結果將出現在您的拉取請求中,您的歷史記錄將在其控制面板中提供。 Node assert (斷言) 斷言是什么 assert 模塊提供了一組簡單的斷言測試,可用于測試不變量。 存在嚴格模式(strict)和遺留模式(legacy...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 3870·2021-09-10 11:22
閱讀 2325·2021-09-03 10:30
閱讀 3660·2019-08-30 15:55
閱讀 1873·2019-08-30 15:44
閱讀 841·2019-08-30 15:44
閱讀 582·2019-08-30 14:04
閱讀 3042·2019-08-29 17:18
閱讀 1262·2019-08-29 15:04