
Promise的重要性我認(rèn)為沒有必要多講,概括起來說就是四個(gè)字:必!須!得!掌!握!。
而且還要掌握透徹。這篇文章的開頭,主要分析一下,為什么會(huì)有Promise出現(xiàn)。
在實(shí)際的使用中,有非常多的應(yīng)用場(chǎng)景我們不能立即知道應(yīng)該如何繼續(xù)往下執(zhí)行。最常見的一個(gè)場(chǎng)景就是ajax請(qǐng)求。通俗來說,由于網(wǎng)速的不同,可能你得到返回值的時(shí)間也是不同的,這個(gè)時(shí)候我們就需要等待,結(jié)果出來了之后才知道怎么樣繼續(xù)下去。
// 簡(jiǎn)單的ajax原生實(shí)現(xiàn)
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var result;
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4 && XHR.status == 200) {
result = XHR.response;
console.log(result);
}
}
在ajax的原生實(shí)現(xiàn)中,利用了onreadystatechange事件,當(dāng)該事件觸發(fā)并且符合一定條件時(shí),才能拿到想要的數(shù)據(jù),之后才能開始處理數(shù)據(jù)。
這樣做看上去并沒有什么麻煩,但如果這個(gè)時(shí)候,我們還需要另外一個(gè)ajax請(qǐng)求,這個(gè)新ajax請(qǐng)求的其中一個(gè)參數(shù),得從上一個(gè)ajax請(qǐng)求中獲取,這個(gè)時(shí)候我們就不得不等待上一個(gè)接口請(qǐng)求完成之后,再請(qǐng)求后一個(gè)接口。如下:
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var result;
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4 && XHR.status == 200) {
result = XHR.response;
console.log(result);
// 偽代碼
var url2 = 'http:xxx.yyy.com/zzz?ddd=' + result.someParams;
var XHR2 = new XMLHttpRequest();
XHR2.open('GET', url, true);
XHR2.send();
XHR2.onreadystatechange = function() {
...
}
}
}
當(dāng)出現(xiàn)第三個(gè)ajax(甚至更多)仍然依賴上一個(gè)請(qǐng)求時(shí),我們的代碼就變成了一場(chǎng)災(zāi)難。這場(chǎng)災(zāi)難,往往也被稱為回調(diào)地獄。
因此我們需要一個(gè)叫做Promise的東西,來解決這個(gè)問題。
當(dāng)然,除了回調(diào)地獄之外,還有一個(gè)非常重要的需求:為了代碼更加具有可讀性和可維護(hù)性,我們需要將數(shù)據(jù)請(qǐng)求與數(shù)據(jù)處理明確的區(qū)分開來。上面的寫法,是完全沒有區(qū)分開,當(dāng)數(shù)據(jù)變得復(fù)雜時(shí),也許我們自己都無法輕松維護(hù)自己的代碼了。這也是模塊化過程中,必須要掌握的一個(gè)重要技能,請(qǐng)一定重視。
從前面幾篇文中的知識(shí)我們可以知道,當(dāng)我們想要確保某代碼在誰誰之后執(zhí)行時(shí),我們可以利用函數(shù)調(diào)用棧,將我們想要執(zhí)行的代碼放入回調(diào)函數(shù)中。
// 一個(gè)簡(jiǎn)單的封裝
function want() {
console.log('這是你想要執(zhí)行的代碼');
}
function fn(want) {
console.log('這里表示執(zhí)行了一大堆各種代碼');
// 其他代碼執(zhí)行完畢,最后執(zhí)行回調(diào)函數(shù)
want && want();
}
fn(want);
利用回調(diào)函數(shù)封裝,是我們?cè)诔鯇W(xué)JavaScript時(shí)常常會(huì)使用的技能。
確保我們想要的代碼壓后執(zhí)行,除了利用函數(shù)調(diào)用棧的執(zhí)行順序之外,我們還可以利用上一篇文章所述的隊(duì)列機(jī)制。
function want() {
console.log('這是你想要執(zhí)行的代碼');
}
function fn(want) {
// 將想要執(zhí)行的代碼放入隊(duì)列中,根據(jù)事件循環(huán)的機(jī)制,我們就不用非得將它放到最后面了,由你自由選擇
want && setTimeout(want, 0);
console.log('這里表示執(zhí)行了一大堆各種代碼');
}
fn(want);
如果瀏覽器已經(jīng)支持了原生的Promise對(duì)象,那么我們就知道,瀏覽器的js引擎里已經(jīng)有了Promise隊(duì)列,這樣就可以利用Promise將任務(wù)放在它的隊(duì)列中去。
function want() {
console.log('這是你想要執(zhí)行的代碼');
}
function fn(want) {
console.log('這里表示執(zhí)行了一大堆各種代碼');
// 返回Promise對(duì)象
return new Promise(function(resolve, reject) {
if (typeof want == 'function') {
resolve(want);
} else {
reject('TypeError: '+ want +'不是一個(gè)函數(shù)')
}
})
}
fn(want).then(function(want) {
want();
})
fn('1234').catch(function(err) {
console.log(err);
})
看上去變得更加復(fù)雜了??墒谴a變得更加健壯,處理了錯(cuò)誤輸入的情況。
為了更好的往下擴(kuò)展Promise的應(yīng)用,這里需要先跟大家介紹一下Promsie的基礎(chǔ)知識(shí)。
一、 Promise對(duì)象有三種狀態(tài),他們分別是:
- pending: 等待中,或者進(jìn)行中,表示還沒有得到結(jié)果
- resolved(Fulfilled): 已經(jīng)完成,表示得到了我們想要的結(jié)果,可以繼續(xù)往下執(zhí)行
- rejected: 也表示得到結(jié)果,但是由于結(jié)果并非我們所愿,因此拒絕執(zhí)行
這三種狀態(tài)不受外界影響,而且狀態(tài)只能從pending改變?yōu)閞esolved或者rejected,并且不可逆。在Promise對(duì)象的構(gòu)造函數(shù)中,將一個(gè)函數(shù)作為第一個(gè)參數(shù)。而這個(gè)函數(shù),就是用來處理Promise的狀態(tài)變化。
new Promise(function(resolve, reject) {
if(true) { resolve() };
if(false) { reject() };
})
上面的resolve和reject都為一個(gè)函數(shù),他們的作用分別是將狀態(tài)修改為resolved和rejected。
二、 Promise對(duì)象中的then方法,可以接收構(gòu)造函數(shù)中處理的狀態(tài)變化,并分別對(duì)應(yīng)執(zhí)行。then方法有2個(gè)參數(shù),第一個(gè)函數(shù)接收resolved狀態(tài)的執(zhí)行,第二個(gè)參數(shù)接收reject狀態(tài)的執(zhí)行。
function fn(num) {
return new Promise(function(resolve, reject) {
if (typeof num == 'number') {
resolve();
} else {
reject();
}
}).then(function() {
console.log('參數(shù)是一個(gè)number值');
}, function() {
console.log('參數(shù)不是一個(gè)number值');
})
}
fn('hahha');
fn(1234);
then方法的執(zhí)行結(jié)果也會(huì)返回一個(gè)Promise對(duì)象。因此我們可以進(jìn)行then的鏈?zhǔn)綀?zhí)行,這也是解決回調(diào)地獄的主要方式。
function fn(num) {
return new Promise(function(resolve, reject) {
if (typeof num == 'number') {
resolve();
} else {
reject();
}
})
.then(function() {
console.log('參數(shù)是一個(gè)number值');
})
.then(null, function() {
console.log('參數(shù)不是一個(gè)number值');
})
}
fn('hahha');
fn(1234);
then(null, function() {}) 就等同于catch(function() {})
三、Promise中的數(shù)據(jù)傳遞
大家自行從下面的例子中領(lǐng)悟吧。
var fn = function(num) {
return new Promise(function(resolve, reject) {
if (typeof num == 'number') {
resolve(num);
} else {
reject('TypeError');
}
})
}
fn(2).then(function(num) {
console.log('first: ' + num);
return num + 1;
})
.then(function(num) {
console.log('second: ' + num);
return num + 1;
})
.then(function(num) {
console.log('third: ' + num);
return num + 1;
});
// 輸出結(jié)果
first: 2
second: 3
third: 4
OK,了解了這些基礎(chǔ)知識(shí)之后,我們?cè)倩剡^頭,利用Promise的知識(shí),對(duì)最開始的ajax的例子進(jìn)行一個(gè)簡(jiǎn)單的封裝??纯磿?huì)是什么樣子。
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
// 封裝一個(gè)get請(qǐng)求的方法
function getJSON(url) {
return new Promise(function(resolve, reject) {
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4) {
if (XHR.status == 200) {
try {
var response = JSON.parse(XHR.responseText);
resolve(response);
} catch (e) {
reject(e);
}
} else {
reject(new Error(XHR.statusText));
}
}
}
})
}
getJSON(url).then(resp => console.log(resp));
為了健壯性,處理了很多可能出現(xiàn)的異常,總之,就是正確的返回結(jié)果,就resolve一下,錯(cuò)誤的返回結(jié)果,就reject一下。并且利用上面的參數(shù)傳遞的方式,將正確結(jié)果或者錯(cuò)誤信息通過他們的參數(shù)傳遞出來。
現(xiàn)在所有的庫(kù)幾乎都將ajax請(qǐng)求利用Promise進(jìn)行了封裝,因此我們?cè)谑褂胘Query等庫(kù)中的ajax請(qǐng)求時(shí),都可以利用Promise來讓我們的代碼更加優(yōu)雅和簡(jiǎn)單。這也是Promise最常用的一個(gè)場(chǎng)景,因此我們一定要非常非常熟悉它,這樣才能在應(yīng)用的時(shí)候更加靈活。
四、Promise.all
當(dāng)有一個(gè)ajax請(qǐng)求,它的參數(shù)需要另外2個(gè)甚至更多請(qǐng)求都有返回結(jié)果之后才能確定,那么這個(gè)時(shí)候,就需要用到Promise.all來幫助我們應(yīng)對(duì)這個(gè)場(chǎng)景。
Promise.all接收一個(gè)Promise對(duì)象組成的數(shù)組作為參數(shù),當(dāng)這個(gè)數(shù)組所有的Promise對(duì)象狀態(tài)都變成resolved或者rejected的時(shí)候,它才會(huì)去調(diào)用then方法。
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
var url1 = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-03-26/2017-06-10';
function renderAll() {
return Promise.all([getJSON(url), getJSON(url1)]);
}
renderAll().then(function(value) {
// 建議大家在瀏覽器中看看這里的value值
console.log(value);
})
五、 Promise.race
與Promise.all相似的是,Promise.race都是以一個(gè)Promise對(duì)象組成的數(shù)組作為參數(shù),不同的是,只要當(dāng)數(shù)組中的其中一個(gè)Promsie狀態(tài)變成resolved或者rejected時(shí),就可以調(diào)用.then方法了。而傳遞給then方法的值也會(huì)有所不同,大家可以再瀏覽器中運(yùn)行下面的例子與上面的例子進(jìn)行對(duì)比。
function renderRace() {
return Promise.race([getJSON(url), getJSON(url1)]);
}
renderRace().then(function(value) {
console.log(value);
})
嗯,我所知道的,關(guān)于Promise的基礎(chǔ)知識(shí)就這些了,如果還有別的,歡迎大家補(bǔ)充。
那么接下來,我們要結(jié)合三個(gè)不同的應(yīng)用場(chǎng)景來讓大家感受一下Promise在模塊系統(tǒng)中如何使用。
這里選擇requirejs是因?yàn)閷W(xué)習(xí)成本最低,能夠快速上手進(jìn)行簡(jiǎn)單的運(yùn)用。接下來的這些例子,會(huì)涉及到很多其他的知識(shí),因此如果想要徹底掌握,一定要?jiǎng)邮謱?shí)踐,自己試著完成一遍。
我在github上創(chuàng)建了對(duì)應(yīng)的項(xiàng)目,大家可以直接clone下來進(jìn)行學(xué)習(xí)。這樣學(xué)習(xí)效果會(huì)更好。
項(xiàng)目地址: https://github.com/yangbo5207/promiseApps
往下閱讀例子之前,請(qǐng)一定要對(duì)requirejs有一個(gè)簡(jiǎn)單的了解。
requirejs中文文檔 http://www.requirejs.cn/

項(xiàng)目的代碼結(jié)果如上圖所示,所有的html文件都放在根目錄下。
- pages: html直接引入的js
- libs: 常用的庫(kù)
- components: 針對(duì)項(xiàng)目自定義的模塊
首先為了能夠讓require起作用,我們需要在html中引入require.js,寫法如下:
// index.js為入口文件
<script data-main="./pages/index.js" src="./libs/require.js"></script>
在入口的index.js中,我們可以對(duì)常用的模塊進(jìn)行映射配置,這樣在引入時(shí)就可以少寫一些代碼。
// 具體的配置項(xiàng)的含義,請(qǐng)參閱require的中文文檔
requirejs.config({
baseUrl: './',
paths: {
jquery: "./libs/jquery-3.2.0",
API: './libs/API',
request: './libs/request',
calendar: './components/calendar',
imageCenter: './components/imageCenter',
dialog: './components/Dialog'
}
})
配置之后,那么我們?cè)谄渌K中,引入配置過的模塊,就可以簡(jiǎn)單的這樣寫:
var $ = require('jquery');
如果不進(jìn)行配置,也可以這樣引入模塊:
require('./components/button');
我們可以使用define定義一個(gè)模塊:
// 其他方式請(qǐng)參閱文檔
define(function(require) {
})
使用return可以直接對(duì)外提供方法:
// 在其他模塊通過require引入時(shí)得到的值,就是這里返回的值
define(function(require) {
return {
a: 1
}
})
OK,了解上面這些,應(yīng)付基礎(chǔ)的使用已經(jīng)沒有問題了。我們接下來重點(diǎn)總結(jié)第一個(gè)常用的應(yīng)用場(chǎng)景:ajax。
關(guān)于ajax的簡(jiǎn)單使用和簡(jiǎn)單封裝,我們?cè)谏厦娑家呀?jīng)講過了,這里就不再多說,直接使用jquery封裝好的方法即可。而我們需要處理的問題在于,如何有效的將ajax的數(shù)據(jù)請(qǐng)求和數(shù)據(jù)處理分別放在不同的模塊中進(jìn)行管理,這樣做的主要目的在于降低后期維護(hù)成本,便于管理。
來看看怎么樣簡(jiǎn)單操作的。
首先,將所有的url放在一個(gè)模塊中統(tǒng)一處理。
// libs/API.js
define(function() {
return {
dayInfo: 'https://hq.tigerbrokers.com/fundamental/finance_calendar/get_day/2017-04-03',
typeInfo: 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-03-26/2017-04-15'
}
})
在實(shí)際開發(fā)中,url并不是直接通過字符串就能直接確認(rèn)的,某些url還需要通過參數(shù)拼接等,這個(gè)時(shí)候需要我們靈活處理。
第二步,將所有的數(shù)據(jù)請(qǐng)求這個(gè)動(dòng)作放在同一個(gè)模塊中統(tǒng)一管理。
// libs/request.js
define(function(require) {
var API = require('API');
// 因?yàn)閖Query中的get方法也是通過Promise進(jìn)行了封裝,最終返回的是一個(gè)Promise對(duì)象,因此這樣我們就可以將數(shù)據(jù)請(qǐng)求與數(shù)據(jù)處理放在不同的模塊
// 這樣我們就可以使用一個(gè)統(tǒng)一的模塊來管理所有的數(shù)據(jù)請(qǐng)求
// 獲取當(dāng)天的信息
getDayInfo = function() {
return $.get(API.dayInfo);
}
// 獲取type信息
getTypeInfo = function() {
return $.get(API.typeInfo);
};
return {
getDayInfo: getDayInfo,
getTypeInfo: getTypeInfo
}
});
在這個(gè)模塊中,我們還可以對(duì)拿到的數(shù)據(jù)進(jìn)行一些你需要的過濾處理,確保最終返回給下一個(gè)模塊的數(shù)據(jù)是能夠直接使用的。
第三步:就是拿到數(shù)據(jù)并且處理數(shù)據(jù)了。
// components/calendar.js
define(function(require) {
var request = require('request');
// 拿到數(shù)據(jù)之后,需要處理的組件,可以根據(jù)數(shù)據(jù)渲染出需求想要的樣式
// 當(dāng)然這里為了簡(jiǎn)化,就僅僅只是輸出數(shù)據(jù)就行了,在實(shí)際中,拿到數(shù)據(jù)之后還要進(jìn)行相應(yīng)的處理
request.getTypeInfo()
.then(function(resp) {
// 拿到數(shù)據(jù),并執(zhí)行處理操作
console.log(resp);
})
// 這樣,我們就把請(qǐng)求數(shù)據(jù),與處理數(shù)據(jù)分離開來,維護(hù)起來就更加方便了,代碼結(jié)構(gòu)也足夠清晰
})
這就是我所了解的處理ajax的比較好的一個(gè)方式,如果你有其他更好的方式也歡迎分享。
第二個(gè)應(yīng)用場(chǎng)景就是圖片加載的問題。
在一些實(shí)際應(yīng)用中,常常會(huì)有一些圖片需要放置在某一個(gè)塊中,比如頭像,比如某些圖片列表??墒窃磮D片的尺寸可能很難保證長(zhǎng)寬比例都是一致的,如果我們直接給圖片設(shè)定寬高,就有可能導(dǎo)致圖片變形。變形之后高大上的頁面就直接垮掉了。
因此為了解決這個(gè)問題,我們需要一個(gè)定制的image組件來解決這個(gè)問題。我們期望圖片能夠根據(jù)自己的寬高比,合理的縮放,保證在這個(gè)塊中不變形的情況下盡可能的顯示更多的內(nèi)容。
假如有一堆圖片,如下:
<section class="img-wrap">
<div class="img-center">

</div>
<div class="img-center">

</div>
<div class="img-center">

</div>
<div class="img-center">

</div>
</section>
每一張圖片都有一個(gè)包裹的div,這些div的寬高,就是我們期望圖片能保持的寬高。
當(dāng)圖片寬度值過大時(shí),我們期望圖片的高度為100%,并且左右居中。
當(dāng)圖片高度值過大時(shí),我們期望圖片的寬度為100%,并且上下居中。
根據(jù)這一點(diǎn),我們來看看具體怎么實(shí)現(xiàn)。
首先是樣式的定義很重要。
.img-center {
width: 200px;
height: 150px;
margin: 20px;
overflow: hidden;
position: relative;
}
.img-center img {
display: block;
position: absolute;
}
.img-center img.aspectFill-x {
width: 100%;
top: 50%;
transform: translateY(-50%);
}
.img-center img.aspectFill-y {
height: 100%;
left: 50%;
transform: translateX(-50%);
}
我分別定義了aspectFill-x與aspectFill-y,通過判斷不同的寬高比,來決定將他們中的其中一個(gè)加入到img標(biāo)簽的class中去即可。
獲取圖片的原始寬高,需要等到圖片加載完畢之后才能獲取。而當(dāng)圖片已經(jīng)存在緩存時(shí),則有一個(gè)compete屬性變成true。那么我們就可以根據(jù)這些基礎(chǔ)知識(shí),定義一個(gè)模塊來處理這件事情。
// components/imageCenter.js
define(function(require) {
// 利用Promise封裝一個(gè)加載函數(shù),這里也是可以單獨(dú)放在一個(gè)功能模塊中進(jìn)一步優(yōu)化
var imageLoad = function(img) {
return new Promise(function(resolve, reject) {
if (img.complete) {
resolve();
} else {
img.onload = function(event) {
resolve(event);
}
img.onerror = function(err) {
reject(err);
}
}
})
}
var imageCenter = function(domList, mode) {
domList.forEach(function(item) {
var img = item.children[0];
var itemW = item.offsetWidth;
var itemH = item.offsetHeight;
var itemR = itemW / itemH;
imageLoad(img).then(function() {
var imgW = img.naturalWidth;
var imgH = img.naturalHeight;
var imgR = imgW / imgH;
var resultMode = null;
switch (mode) {
// 這樣寫是因?yàn)槠诖磥砜梢詳U(kuò)展其他的展示方式
case 'aspectFill':
resultMode = imgR > 1 ? 'aspectFill-x' : 'aspectFill-y';
break;
case 'wspectFill':
resultMode = itemR > imgR ? 'aspectFill-x' : 'aspectFill-y'
break;
default:
}
$(img).addClass(resultMode);
})
})
}
return imageCenter;
})
那么在使用時(shí),直接引入這個(gè)模塊并調(diào)用imageCenter方法即可。
// index.js
var imageCenter = require('imageCenter');
var imageWrapList = document.querySelectorAll('.img-center');
imageCenter(imageWrapList, 'wspectFill');

第三個(gè)應(yīng)用場(chǎng)景,則是自定義彈窗的處理。

因此自己專門定義一個(gè)常用的彈窗就變得非常有必要,這對(duì)于我們開發(fā)效率的提高非常有幫助。當(dāng)然,我這里只是簡(jiǎn)單的寫了一個(gè)簡(jiǎn)陋的,僅供參考。
我們期望的是利用Promise,當(dāng)我們點(diǎn)擊確認(rèn)時(shí),狀態(tài)變成resolved,點(diǎn)擊取消時(shí),狀態(tài)變成rejected。這樣也方便將彈窗生成與后續(xù)的操作處理區(qū)分開來。
先定義一個(gè)Dialog模塊。使用的是最簡(jiǎn)單的方式定義,應(yīng)該不會(huì)有什么理解上的困難。主要提供了show和hide2個(gè)方法,用于展示和隱藏。
// components/Dialog.js
define(function(require) {
// 利用閉包的特性,判斷是否已經(jīng)存在實(shí)例
var instance;
function Dialog(config) {
this.title = config.title ? config.title : '這是標(biāo)題';
this.content = config.content ? config.content : '這是提示內(nèi)容';
this.html = '<div class="dialog-dropback">' +
'<div class="container">' +
'<div class="head">'+ this.title +'</div>' +
'<div class="content">'+ this.content +'</div>' +
'<div class="footer">' +
'<button class="cancel">取消</button>' +
'<button class="confirm">確認(rèn)</button>' +
'</div>' +
'</div>' +
'</div>'
}
Dialog.prototype = {
constructor: Dialog,
show: function() {
var _this = this;
if (instance) {
this.destory();
}
$(this.html).appendTo($(document.body));
instance = this;
return new Promise(function(resolve, reject) {
$('.dialog-dropback .cancel').on('click', function(e) {
_this.hide();
reject(e);
})
$('.dialog-dropback .confirm').on('click', function(e) {
_this.hide();
resolve(e);
})
})
},
destory: function() {
instance = null;
$('.dialog-dropback .cancel').off('click');
$('.dialog-dropback .confirm').off('click');
$('.dialog-dropback').remove();
},
hide: function() {
this.destory();
}
}
return function(config) {
return new Dialog(config);
}
})
那么在另外一個(gè)模塊中需要使用它時(shí):
define(function(require) {
var Dialog = require('dialog');
$('button.aspect').on('click', function() {
Dialog({
title: '友情提示',
content: '外面空氣不太好,你確定你要出門逛逛嗎?'
}).show().then(function() {
console.log('你點(diǎn)擊了確認(rèn)按鈕.');
}).catch(function() {
console.log('你點(diǎn)擊了取消按鈕.');
})
})
})
這三種場(chǎng)景就介紹完了,主要是需要大家通過源碼來慢慢理解和揣摩。真正掌握之后,相信大家對(duì)于Promise在另外的場(chǎng)景中的使用也會(huì)變得得心應(yīng)手。
最后總結(jié)一下,這篇文章,涉及到的東西,有點(diǎn)多。大概包括Promise基礎(chǔ)知識(shí),ajax基礎(chǔ)知識(shí),如何利用Promise封裝ajax,如何使用require模塊系統(tǒng),如何在模塊中使用Promise,并且對(duì)應(yīng)的三個(gè)應(yīng)用場(chǎng)景又各自有許多需要了解的知識(shí),因此對(duì)于基礎(chǔ)稍差的朋友來說,理解透徹了肯定會(huì)有一個(gè)比較大的進(jìn)步。當(dāng)然也會(huì)花費(fèi)你更多的時(shí)間。
另外在我們的工作中還有一件非常重要的事情是需要我們持續(xù)去做的。那就是將常用的場(chǎng)景封裝成為可以共用的模塊,等到下次使用時(shí),就可以直接拿來使用而節(jié)省非常多的開發(fā)時(shí)間。比如我這里對(duì)于img的處理,對(duì)于彈窗的處理,都是可以擴(kuò)展成為一個(gè)通用的模塊的。慢慢積累多了,你的開發(fā)效率就可以得到明顯的提高,這些積累,也將會(huì)變成你的優(yōu)勢(shì)所在。
后續(xù)的文章我會(huì)分享如何利用react與es6模塊系統(tǒng)封裝的共用組件,大家也可以學(xué)習(xí)了之后,根據(jù)自己的需求,封裝最適合你自己的一套組件。
最后,最近問我怎么學(xué)習(xí)的人越來越多,我真的有點(diǎn)回答不過來了,我想把我這些文章里的知識(shí)都掌握了,應(yīng)付畢業(yè)之后的第一份工作應(yīng)該不是什么問題的吧?而且為了你們能夠掌握Promise的使用,我還專門給讀者老爺們創(chuàng)建了一個(gè)項(xiàng)目,列舉了整整三個(gè)實(shí)例,還有源代碼供你們學(xué)習(xí),我學(xué)Promise的時(shí)候,找好久都沒找到一個(gè)稍微接近實(shí)際應(yīng)用的案例,學(xué)了好久才知道怎么使用,效率之低可想而知。所以靜下心來慢慢學(xué)習(xí)吧,花點(diǎn)時(shí)間是值得的 ~ ~ 。