TIL coding
  • Initial page
  • 排版
  • Flexbox
  • Grid
  • jQuery
  • Untitled
  • JavaScript
    • An Introduction to JavaScript
    • Hello, world!
    • Code structure
    • The modern mode, "use strict"
    • Variables
    • Data types
    • Type Conversions
    • Operators
    • Comparisons
    • Interaction: alert, prompt, confirm
    • Conditional operators: if, '?'
    • Logical operators
    • Loops: while and for
    • The "switch" statement
    • Functions
    • Function expressions and arrows
    • JavaScript specials
    • Comments
    • Ninja code
    • Automated testing with mocha
    • Polyfills
    • Objects
    • Garbage collection
    • Symbol type
    • Object methods, "this"
    • Object to primitive conversion
    • Constructor, operator "new"
    • Methods of primitives
    • Numbers
    • Strings
    • Arrays
    • Array methods
    • Iterables
    • Map, Set, WeakMap and WeakSet
    • Object.keys, values, entries
    • Destructuring assignment
    • Date and time
    • JSON methods, toJSON
    • Recursion and stack
    • Rest parameters and spread operator
    • Closure
    • The old "var"
    • Global object
    • Function object, NFE
    • The "new Function" syntax
    • Scheduling: setTimeout and setInterval
    • Decorators and forwarding, call/apply
    • Function binding
    • Currying and partials
    • Arrow functions revisited
    • Property flags and descriptors
    • Property getters and setters
    • Prototypal inheritance
    • F.prototype
    • Native prototypes
    • Prototype methods, objects without __proto__
    • The “class” syntax
    • Class inheritance
    • Static properties and methods
    • Private and protected properties and methods
    • Extending built-in classes
    • Class checking: "instanceof"
    • Mixins
    • Error handling, "try..catch"
    • Custom errors, extending Error
    • Introduction: callbacks
    • Promise
    • Promises chaining
    • Error handling with promises
    • Promise API
  • Bootstrap
    • Navbar
Powered by GitBook
On this page
  • Consumers: then, catch, finally
  • then
  • catch
  • finally
  • Example: loadScript

Was this helpful?

  1. JavaScript

Promise

PreviousIntroduction: callbacksNextPromises chaining

Last updated 5 years ago

Was this helpful?

想像有一位超級歌星,粉絲日以繼夜關心專輯什麼時候出,這位超級歌星很煩惱,因此想出了一個辦法,讓粉絲追蹤他的 IG ,若有任何關於他的消息都可以第一時間知道。 在編寫程式碼也會遇到一樣的問題: 1. 生產程式碼:作一些事需要時間,像是加載腳本,腳色是歌手。 2. 消費程式碼:知道生產程式碼的結果,不論有沒有成功,腳色是粉絲。 3. promise 是連接 2 者的橋樑,生產程式碼的結果會保證傳到每個消費程式碼,腳色是 IG。

// syntax,executor 是生產程式碼,最終會產生結果,傳到 promise,promise 物件有 2 個內部屬性,
// state 描述 promise 狀態,一開始 pedding => fullfilled or rejected
// result 任意值,一開始 undefined => value or error
let promise = new Promise(function(resolve, reject) {
  // executor (生产者代码,"singer")
});
// 會自動呼叫 executor,executor 會接收 resolve、reject 2 個參數。
let promise = new Promise(function(resolve, reject) {
  // the function is executed automatically when the promise is constructed

  // after 1 second signal that the job is done with the result "done"
  setTimeout(() => resolve("done"), 1000);
});
let promise = new Promise(function(resolve, reject) {
  // after 1 second signal that the job is finished with an error
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});
// executor 只會有一個結果,另一個結果會被忽略。
let promise = new Promise(function(resolve, reject) {
  resolve("done");

  reject(new Error("…")); // 被忽略
  setTimeout(() => resolve("…")); // 被忽略
});

// 可以使用任何類型的參數帶入 reject,但建議使用 Error 物件

// 通常 executor 會執行一些異步程式,這時需要一些時間才能得到結果。我們可以立即返回結果,當任務
// 已經完成。
let promise = new Promise(function(resolve, reject) {
  // not taking our time to do the job
  resolve(123); // immediately give the result: 123
});

// promise 的內建屬性 state and result,不能從消費程式碼取得,但可以透過
// .then/.catch/.finally 等方法取得

Consumers: then, catch, finally

消費程式碼可以得知生產結果,透過 .then, .catch and .finally等方法。

then

// syntax,成功時執行第 1 個參數,失敗時執行第 2 個參數
promise.then(
  function(result) { /* handle a successful result */ },
  function(error) { /* handle an error */ }
);

// 成功
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);
});

// resolve runs the first function in .then
promise.then(
  result => alert(result), // shows "done!" after 1 second
  error => alert(error) // doesn't run
);

// 失敗
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// reject runs the second function in .then
promise.then(
  result => alert(result), // doesn't run
  error => alert(error) // shows "Error: Whoops!" after 1 second
);

// 只返回成功結果
let promise = new Promise(resolve => {
  setTimeout(() => resolve("done!"), 1000);
});

promise.then(alert); // shows "done!" after 1 second

catch

// 只返回失敗結果,可以用 .then(null, errorHandlingFunction) 或 .catch(errorHandlingFunction)
// .catch(f) 是 .then(null, f) 的簡寫
let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// .catch(f) is the same as promise.then(null, f)
promise.catch(alert); // shows "Error: Whoops!" after 1 second

finally

// 就像 try {...} catch {...} 有 finally,promise 也有 finally
// .finally(f) 很像 .then(f, f),當 promise 完成他會被執行無論成功或失敗。
// finally 適合使用在清空記憶體
new Promise((resolve, reject) => {
  /* do something that takes time, and then call resolve/reject */
})
  // runs when the promise is settled, doesn't matter successfully or not
  .finally(() => stop loading indicator)
  .then(result => show result, err => show error)
  
// .finally(f) 跟 .then(f, f) 的差別
// 1. finally 沒有參數
// 2. finally 傳遞 result 參數
// 成功
new Promise((resolve, reject) => {
  setTimeout(() => resolve("result"), 2000)
})
  .finally(() => alert("Promise ready"))
  .then(result => alert(result)); // <-- .then handles the result

// 失敗
new Promise((resolve, reject) => {
  throw new Error("error");
})
  .finally(() => alert("Promise ready"))
  .catch(err => alert(err));  // <-- .catch handles the error object
 
// 3. .finally(f) 比 .then(f, f) 簡潔

// 當 promise 執行完畢結果會立即回傳
// an immediately resolved promise
let promise = new Promise(resolve => resolve("done!"));

promise.then(alert); // done! (shows up right now)

Example: loadScript

function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;

  script.onload = () => callback(null, script);
  script.onerror = () => callback(new Error(`Script load error for ${src}`));

  document.head.append(script);
}

// 重新改寫
function loadScript(src) {
  return new Promise(function(resolve, reject) {
    let script = document.createElement('script');
    script.src = src;

    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error(`Script load error for ${src}`));

    document.head.append(script);
  });
}

// 使用
let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js");

promise.then(
  script => alert(`${script.src} is loaded!`),
  error => alert(`Error: ${error.message}`)
);

promise.then(script => alert('One more handler to do something else!'));

Promises

Callbacks

Promises allow us to do things in the natural order. First, we run loadScript(script), and .then we write what to do with the result.

We must have a callback function at our disposal when calling loadScript(script, callback). In other words, we must know what to do with the result before loadScript is called.

There can be only one callback.

We can call .then on a Promise as many times as we want. Each time, we’re adding a new “fan”, a new subscribing function, to the “subscription list”. More about this in the next chapter: .

Promises chaining