2014-05-21 85 views
2

我對JavaScript進行了相當的代碼編寫,雖然我認爲我確實瞭解承諾的工作原理,但我不確定是否完全理解承諾爲JS世界帶來的優勢。考慮下面的代碼,簡單地說帶有包含更多調用的回調的異步調用等等。瞭解JavaScript中的承諾

(function doWorkOldSchool() { 

    setTimeout(function() { 

     // once done resolve promise 

     console.log("work done"); 

     setTimeout(function goHome() { 

      // once done resolve promise 

      console.log("got home"); 

      try { 

       setTimeout(function cookDinner() { 

        // this exception will not be caught 

        throw "No ingredients for dinner!"; 
        console.log("dinner cooked"); 

        setTimeout(function goToSleep() { 

         // once done resolve promise 

         console.log("go to sleep"); 

        }, 2000); 

       }, 2000); 

      } catch (ex) { 
       console.log(ex); 
      } 

     }, 2000); 

    }, 2000); 

}()); 

一個問題,我這個看:

  1. 例外回調的內部拋出是無用的。是否正確地說,當拋出調用發生時,這些拋出調用超出了範圍,因此這個異常不能被調用並且一直到達頂部?這種例外如何處理?

  2. 第二個問題我發現這個嵌套業務可能會非常深入,即使您可以在setTimeout代碼之外保留回調函數代碼,它可能會變得一團糟。

因此,有人可以先澄清一下,如果還有什麼其他問題或者這種編碼的優勢是明顯的嗎?現在

,下面我編寫的程序,做同樣的事情真的,但使用的承諾這一次:

function doWork() { 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("work done"); 

     }, 2000); 

    }); 
} 


function goHome(succ) { 

    console.log(succ); 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("got home"); 

     }, 2000); 

    }); 
} 


function cookDinner(succ) { 

    console.log(succ); 

    //if exception thrown here it will be caught by chained err handler 
    throw "No ingredients for dinner Exception!"; 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // something went wrong so instead of using throw we reject the promise 

      rej("No ingredients for dinner!"); 

      // once done resolve promise 

     }, 2000); 

    }); 
} 


function goToSleep(succ) { 

    console.log(succ); 

    return new Promise(function(res, rej) { 

     // do your asynchronous stuff 

     setTimeout(function() { 

      // once done resolve promise 

      res("zzz... zz.."); 

     }, 2000); 

    }); 
} 


doWork() 
    .then(goHome) 
    .then(cookDinner) 
    .then(goToSleep) 
    .then(function(succ) { 

     console.log(succ); 

    }, function(err) { 
     console.log(err); 
    }); 

以前的解決方案相比我看不出有什麼明顯的問題,通過這種方法,除了你顯然必須理解承諾編碼/維護這件事。然而,其優點是:

  1. 拋出的異常內部處理程序將被捕獲到進一步鏈接到某處的err處理程序中。

  2. 被拒絕的承諾將通過鏈接ERR處理器

  3. 的代碼捕獲,是更清潔

現在,我的理解是否正確,或是否有每種方法的任何其他優勢/劣勢?

+0

是的。是。是。我不會擔心後續的維護工作......承諾是ES6草案的一部分,並且有據可查。額外冗長的代價遠遠高於頂級代碼的可讀性。 – spender

回答

-1

承諾一次只能返回/決定一個值,所以一旦選擇了一個值,它就不能被更改。因此,如果用戶點擊一個div一旦承諾只執行一次
例:

p = new Promise(function (res, rej) { 
var b = document.getElementById('helloWorld'); 
    b.onclick = function() { 
    res(prompt('value')); 
    }; 
}); 
p.then(function(val) { console.log(val); }); 

總會有隻有一個值,該值將在日誌中。 這對於遊戲/應用程序的GUI和控件很有用。 你也可以在Promise中有兩個事件監聽器,這對加載圖像和文件很有用。即使在添加成功或失敗處理程序後,Promise也會作出反應,因此您創建了一個成功函數,儘管稍後會創建失敗函數,但如果失敗,常規事件處理程序會生成錯誤,但Promises不會在稍後調用該函數它被創建。這使您可以更專注於如何對事件做出反應,而不必擔心事物的時間安排。加載事物非常有用。
Amazing Page On Promises

0

您的代碼使用了一些反模式,您不應該創建承諾(例如,通過new Promise,「延期」等)在應用程序代碼。你也不能混合使用回調和承諾,因爲這樣你就失去了異常冒泡(承諾的要點)並且讓你的代碼超級冗長。

您可以使用圖書館或實現自己的延遲:

function delay(ms, val) { 
    return new Promise(function(res){setTimeout(res.bind(null, val), ms);}); 
} 

然後:

function doWork() { 
    return delay(2000, "work done"); 
} 

doWork() 
    .then(function(succ) { 
     console.log(succ); 
     return delay(2000, "got home"); 
    }) 
    .then(function(succ) { 
     console.log(succ); 
     // Never throw strings, yet another anti-pattern 
     throw new Error("No ingredients for dinner Exception!"); 
     // Pointless to add code after throw 
    }) 
    .then(function(succ) { 
     return delay(2000, "zzz.. zz.."); 
    }) 
    // Don't use the second argument of .then, use .catch 
    .catch(function(err) { 
     console.log("error: ", err); 
    }); 

爲何要用.catch,而不是第二個參數?那麼,比較你會如何寫同步:

try { 
    doWork(); 
    console.log("work done"); 
    sleep(2000); 
    console.log("got home"); 
    sleep(2000); 
    throw new Error("No ingredients for dinner Exception!";) 
    sleep(2000); 
    console.log("zzz.. zz.."); 
} 
catch(e) { 
    console.log("error: ", err); 
} 

得到它?

+0

我不確定我是否理解了你的第一段,你能否詳細說明或指出URL的解釋? – spirytus

+0

@spirytus如果你看看我的代碼並將它與你的代碼進行比較,是不是可以解釋它? :P – Esailija