loadScript函數(shù)
有這么一個(gè)應(yīng)用場(chǎng)景:
我們想要?jiǎng)討B(tài)地加載一個(gè)js腳本,然后調(diào)用腳本中的某個(gè)函數(shù)。所以,這其實(shí)抽象為,我們需要等待一個(gè)異步請(qǐng)求結(jié)果,然后做一些操作。
function loadScript(src,callback){
let script=document.creatElement('script');
script.src=src;
script.onload=()=>{
callback(script);
}
document.head.appendChild(script);
}
我們可以用上述的callback機(jī)制這么來(lái)寫(xiě)。這么寫(xiě)當(dāng)然沒(méi)有問(wèn)題,那么如果我們想要在第一個(gè)腳本加載完成之后,去加載第二個(gè)腳本,我們就需要在callback里面做這件事,那么代碼就會(huì)變成這樣:
loadScript('/src/index.js', (script)=>{
console.log('cool, the first script from '+script.src+' is loaded!');
loadScript('/src/index2.js', (script)=>{
console.log('now the second script from '+script.src+' is loaded.');
}
});
這樣的寫(xiě)法會(huì)出現(xiàn)callback金字塔的代碼結(jié)構(gòu)。所以我們提出讓promise來(lái)解決以上的應(yīng)用場(chǎng)景。
上述場(chǎng)景如果用promise機(jī)制來(lái)寫(xiě)的話(huà),語(yǔ)法會(huì)更加符合邏輯和規(guī)律。
Promise--executor
new Promise((resolve,reject)=>{
//do some stuff
resolve('done');
//or
reject(new Error('error message'));
})
生成一個(gè)新的Promise對(duì)象,會(huì)立刻執(zhí)行executor函數(shù)。
promise 對(duì)象有內(nèi)部屬性:
- state —— 最初是 “pending”,然后被改為 “fulfilled” 或 “rejected”,
- result —— 一個(gè)任意值,最初是 undefined。
當(dāng) executor 完成任務(wù)時(shí),應(yīng)調(diào)用下列之一:
- resolve(value) —— 說(shuō)明任務(wù)已經(jīng)完成:
將 state 設(shè)置為 "fulfilled",sets result to value。 - reject(error) —— 表明有錯(cuò)誤發(fā)生:
將 state 設(shè)置為 "rejected",將 result 設(shè)置為 error。
我們經(jīng)常會(huì)在promise中發(fā)送異步請(qǐng)求,然后去調(diào)用resolve或者reject,實(shí)際上,在executor中立即調(diào)用它們也是可以的。
//常見(jiàn)用法
new Promise(()=>{
console.log(resolve);
console.log(reject);
setTimeout(()=>{
resolve('done');
},1000);
);
Promise--then, catch
當(dāng) promise完成之后,either fulfilled or rejected, 我們可以在promise提供的.then, .catch函數(shù)中做進(jìn)一步的操作。
On settled promises then runs immediately
//when it is resolved
promise.then(
(result)=>console.log(result)
)
// when it is rejected
promise.catch(
(error)=>console.log(error.message)
)
用promise改寫(xiě)loadScript()
function loadScript(src){
return new Promise((resolve,reject)=>{
const script=document.createElement('script');
script.src=src;
document.head.appendChild(script);
script.onload=()=>{resolve(script)};
script.onerror=()=>{reject(new Errror('the script is failed to load '+src))}
})
}
let promise1=loadScript('./index.js');
promise1.then(
(result)=>{console.log(`${result.src} is loaded!`)},
(error)=>{console.log(error.message)}
)
Promise chain
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
要看懂這段代碼,只需要理解:
promise.then((value)=>return 2*value)會(huì)返回一個(gè)新的promise, 狀態(tài)為fulfilled, value為2, 所以我們可以連續(xù)調(diào)用.then(),形成promise chain.
return Promise
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => { // (*)
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) { // (**)
alert(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result * 2), 1000);
});
}).then(function(result) {
alert(result); // 4
});
(*)處返回的是一個(gè)新的promise,js引擎會(huì)一直等到這個(gè)新的promise resolved之后,再去執(zhí)行(**)處的.then函數(shù)。
返回 promises 允許我們建立異步動(dòng)作鏈
應(yīng)用場(chǎng)景:順序加載腳本1,腳本2,腳本3,然后調(diào)用這些腳本里面的函數(shù)(用promise chain來(lái)輕松實(shí)現(xiàn))
function loadScript(src){
return new Promise((resolve,reject)=>{
const script=document.createElement('script');
script.src=src;
script.onload=()=>resolve(script);
script.onerror=()=>reject(new Error(src+ 'failed.'));
document.head.appendChild(script);
}
)
}
loadScript('./index1.js')
.then(script=>loadScript('./index2.js'))
.then(script=>loadScript('./index3.js'))
.then(()=>{
one();
two();
three();
})