避免callback金字塔——promise

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();
})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容