摘要:實現(xiàn)是中的一種異步編程實現(xiàn)方式,中異步編程主要是指瀏覽器事件處理,等,通過傳入回調(diào)函數(shù)來實現(xiàn)控制反轉(zhuǎn)。對象符合編程規(guī)范,目的是為異步編程提供統(tǒng)一接口,它最大的優(yōu)點就是避免了回調(diào)金字塔。
promise實現(xiàn)
Promise是Javascript中的一種異步編程實現(xiàn)方式,js中異步編程主要是指瀏覽器DOM事件處理,setTimeout/setInterval,ajax等,通過傳入回調(diào)函數(shù)來實現(xiàn)控制反轉(zhuǎn)。Promsie對象符合CommonJS編程規(guī)范,目的是為異步編程提供統(tǒng)一接口,它最大的優(yōu)點就是避免了回調(diào)金字塔。
假設(shè)要實現(xiàn)一個用戶展示的任務(wù),任務(wù)分為三步:
獲取用戶信息
獲取用戶圖片
彈窗提示
一般之前使用方式為:
之前已經(jīng)對getUserInfo()和getUserImage(),showTip()方法進行了定義
getUserInfo(id, function(info){ getUserImage(info.img, function(){ showTip(); }) })
如果回調(diào)函數(shù)不止3個,那將會是一個非常長的回調(diào),換成Promise實現(xiàn):
//getUserInfo返回promise getUserInfo(id) .then(getUserImage) .then(showTip) .catch(function(e){ console.log(e); });
簡單的講,Promsie的思想就是每一個異步任務(wù)返回一個promise對象,該對象有一個then方法,允許指定回調(diào)函數(shù)。這里getUserInfo的回調(diào)函數(shù)就是getUserImage。
getUserInfo函數(shù)要進行如下改寫(這里用jQuery的Deferred()實現(xiàn))
function getUserInfo(id){ var dfd = $.Deferred(); setTimeout(function(){ //獲取用戶信息 dfd.resolve(); }, 500); return dfd.promise; }
這樣一種寫法回調(diào)函數(shù)就成了鏈式寫法,程序的流程非常清楚,可以實現(xiàn)多個回調(diào)。
先在ES6出來之后,許多瀏覽器已經(jīng)支持Promise方法,
promise有三種狀態(tài):
pending:初始狀態(tài)
fulfilled:成功操作
rejected:失敗操作
開始的時候promise是pending狀態(tài),fulfill之后就會執(zhí)行回調(diào)then的回調(diào)函數(shù),如果是reject就會調(diào)用catch進行異常處理,Promise.prototype.then() 和 Promise.prototype.catch() 兩種方法狀態(tài)都會返回一個promise對象,用于后續(xù)鏈式調(diào)用。
"use strict"; var promiseCount = 0; function testPromise(){ var thisPromiseCount = promiseCount++; var log = document.getElementById("log"); log.insertAdjacentHTML("beforeend", thisPromiseCount + ") 開始 (異步調(diào)用開始)
"); //新建一個promsie對象 var p1 = new Promise(function(resolve, reject){ log.insertAdjacentHTML("beforeend", thisPromiseCount + ") Promise 開始執(zhí)行 (異步調(diào)用開始)
"); window.setTimeout(function(){ resolve(thisPromiseCount); }, 2000) }); //定義promise執(zhí)行fulfilled執(zhí)行的then()回調(diào)函數(shù)以及執(zhí)行reject后的catch回調(diào)函數(shù) 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接口"; } }
單擊按鈕后,首先執(zhí)行promise
實現(xiàn)XMLHttpRequest獲取數(shù)據(jù)3秒之后resolve調(diào)用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); });構(gòu)建一個簡單的promise模式框架
首先需要建立一個對象來存儲promise
Promise = function(){ this.queue = []; this.value = null; this.status = "pending"; };
定義獲取隊列,設(shè)定狀態(tài)和獲取狀態(tài)原型方法
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方法,接受兩個參數(shù)用于完成和拒絕任務(wù)操作。
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; };
定義三個不同狀態(tài)函數(shù)
Promise.prototype.isFulfilled = function(){ return this.status === "fulfilled"; }; Promise.prototype.isRejected = function(){ return this.status === "rejected"; }; Promise.prototype.isPending = function(){ return this.status === "pending"; };
工具處理函數(shù)
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 } })();
定義延遲函數(shù)
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); }
有很多實現(xiàn)了promises的庫供開發(fā)者可用。 像jQuery的 Deferred, 微軟的 WinJS.Promise, when.js, q, 和dojo.Deferred.
關(guān)于jQuery的Deferred可以參考jQuery的deferred對象詳解
Promise MDN
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79070.html
摘要:標準已于年月份正式定稿了,并廣泛支持最新的特性異步函數(shù)。為了領(lǐng)會,我們需要回到普通回調(diào)函數(shù)中進一步學習。從此編寫回調(diào)函數(shù)不再那么痛苦?;卣{(diào)是一個函數(shù),可以將結(jié)果傳遞給函數(shù)并在該函數(shù)內(nèi)進行調(diào)用,以便作為事件的響應(yīng)。 ES2017標準已于2017年6月份正式定稿了,并廣泛支持最新的特性:異步函數(shù)。如果你曾經(jīng)被異步 JavaScript 的邏輯困擾,這么新函數(shù)正是為你設(shè)計的。 異步函數(shù)或多或...
摘要:斷言斷言是什么模塊提供了一組簡單的斷言測試,可用于測試不變量。環(huán)境是他們不必設(shè)置大量配置的環(huán)境,而是開發(fā)人員可以編寫代碼并從測試中獲得即時反饋的地方。每當測試時,結(jié)果將出現(xiàn)在您的拉取請求中,您的歷史記錄將在其控制面板中提供。 Node assert (斷言) 斷言是什么 assert 模塊提供了一組簡單的斷言測試,可用于測試不變量。 存在嚴格模式(strict)和遺留模式(legacy...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 3882·2021-09-10 11:22
閱讀 2347·2021-09-03 10:30
閱讀 3669·2019-08-30 15:55
閱讀 1901·2019-08-30 15:44
閱讀 849·2019-08-30 15:44
閱讀 594·2019-08-30 14:04
閱讀 3048·2019-08-29 17:18
閱讀 1272·2019-08-29 15:04