約束とは何ですか?約束の概要

Oct 17, 2018 pm 02:55 PM
html5 javascript node.js

この記事の内容はPromiseとは何か? Promiseの紹介は参考になると思います。

実は、Promise の使用法については長い間書きたいと思っていました。 1 つは、実際のコーディングプロセスで頻繁に使用されること、もう 1 つは、友人が使用するときに時々問題が発生することです。

Promise は、ES6 の API 機能の 1 つであり、JS の記述方法に最も大きな影響を与えています。
この記事は実際の使用プロセスをまとめたものです
ファイル作成時刻2017-10-09を見てください、先延ばしは本当にひどいです。 。 。まだまだ実行力を強化する必要があります!初心を忘れずに、さあ!

序文と基本概念

Promise は、従来のコールバック関数と比較して、複数のコールバックの深刻なネストの問題を解決します。

Promise オブジェクトは非同期操作を表し、保留中、完了済み、または拒否済みの 3 つの状態を持ちます。状態遷移は保留中、完了済み、保留中、拒否済みのいずれかになります。このプロセスは一度発生すると元に戻せません。 。

個人的には、Promise の説明は 2 つの部分に分ける必要があると考えています。

  1. Promise コンストラクターの使用説明書。

  2. Promise プロトタイプ オブジェクトのいくつかのメソッド。

Promise コンストラクター

ES6 では、Promise オブジェクトが Promise インスタンスを生成するために使用されるコンストラクターであると規定されています。

Promise コンストラクターは、関数をパラメーターとして受け取ります。関数の 2 つのパラメーターは、resolve と accept です。これらは JavaScript エンジンによって提供される 2 つの関数であり、自分でデプロイする必要はありません。

resolve 関数の役割は、Promise オブジェクトの状態を「未完了」から「成功」に変更することです (つまり、保留中から完了に)。これは、非同期操作が成功したときに呼び出されます。非同期操作の結果は次のように使用されます。パラメータが渡されます。
reject 関数の機能は、Promise オブジェクトのステータスを「未完了」から「失敗」(つまり、保留中から拒否) に変更することです。非同期操作が失敗したときに呼び出され、エラーがパラメーターとして渡されます。

次のコードは Promise インスタンスを作成します。

function request() {
  return new Promise((resolve, reject) => {
    /* 异步操作成功 */
    setTimeout(() => {
      resolve("success");
    }, 1000);
    // 取消注释这里可以体现,Promise 的状态一旦变更就不会再变化的特性
    // reject('error');
  });
}
ログイン後にコピー

Receive

request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });
ログイン後にコピー

上記の new Promise() の後に、catch を使用してエラーをキャプチャすることに加えて、then を使用することもできます。指定するメソッドresolvereject のコールバック関数
もエラーをキャッチする目的を達成できます。

request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);
ログイン後にコピー

プロトタイプのメソッド

Promise.prototype.then()

p.then(onFulfilled, onRejected)
ログイン後にコピー

then メソッドは、上記の例のように、Promise.prototype で定義されたメソッドです。 2 つのパラメータ、満たされたコールバック関数と拒否されたコールバック関数。2 番目のパラメータはオプションです。

2 つの重要なポイント:

  1. then メソッドの戻り値は新しい Promise インスタンスであるため、呼び出し側は A ## を取得します。 #Promise オブジェクトは、then を呼び出した後も Promise を返し、その動作は then のコールバック関数の戻り値に関連します。次のように:

  • then のコールバック関数が値を返す場合、then によって返された Promise は受け入れられた状態になり、返された値が考慮されます。受け入れられた状態としてのコールバック関数のパラメータ値。

  • then のコールバック関数がエラーをスローした場合、then によって返された Promise は拒否状態となり、スローされたエラーは、then のコールバック関数のパラメータ値として使用されます。拒否された状態。

  • then のコールバック関数がすでに受け入れ状態にある Promise を返す場合、then によって返された Promise も受け入れ状態になり、コールバック関数のパラメータはその Promise の受け入れ状態は次のようになります。この値は、返された Promise の受け入れ状態コールバック関数のパラメータ値として使用されます。

  • then のコールバック関数がすでに拒否状態にある Promise を返した場合、then によって返された Promise も拒否状態になり、コールバック関数のパラメータはこの値は、返された Promise の拒否ステータス コールバック関数のパラメータ値として使用されます。

  • then のコールバック関数が未確定状態 (保留中) の Promise を返す場合、then によって返される Promise の状態も保留中となり、その最終状態は次と同じになります。 ;同時に、最終状態になるときに呼び出されるコールバック関数のパラメータは、Promiseが最終状態になるときのコールバック関数のパラメータと同じになります。

    #チェーンコール。ネストされたコールバックのコード形式を、連鎖呼び出しの垂直モードに変換します。
  1. たとえば、コールバック形式: コールバック地獄の例
a(a1 => {
  b(a1, b1 => {
    c(b1, c1 => {
      d(c1, d1 => {
        console.log(d1);
      });
    });
  });
});
ログイン後にコピー

このような水平展開は、(a, b, c, d) all return Promise に変更できます。関数

a()
  .then(b)
  .then(c)
  .then(d)
  .then(d1 => {
    console.log(d1);
  });
//===== 可能上面的例子并不太好看 ===下面这样更直观
a()
  .then(a1 => b(a1))
  .then(b1 => c(b1))
  .then(c1 => d(c1))
  .then(d1 => {
    console.log(d1);
  });
ログイン後にコピー

の垂直構造ははるかにすっきりしています。

Promise.prototype.catch()

then() に加えて、Promise.prototype プロトタイプ チェーンには、拒否状況のハンドラー関数である catch() メソッドもあります。 。

其实 它的行为与调用 Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部 calls obj.then(undefined, onRejected)).

// 1.
request().then(
  result => {
    console.info(result);
  },
  error => {
    console.info(error);
  }
);

// 2.
request()
  .then(result => {
    console.info(result);
  })
  .catch(error => {
    console.info(error);
  });
ログイン後にコピー

如上这个例子:两种方式在使用,与结果基本上是等价的,但是 仍然推荐第二种写法,下面我会给出原因:

  1. 在 Promise 链中 Promise.prototype.then(undefined, onRejected),onRejected 方法无法捕获当前 Promise 抛出的错误,而后续的 .catch 可以捕获之前的错误。

  2. 代码冗余

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(
    result => {
      console.log(result + "1");
      throw Error(result + "1"); // 抛出一个错误
    },
    error => {
      console.log(error + ":1"); // 不会走到这里
    }
  )
  .then(
    result => {
      console.log(result + "2");
      return Promise.resolve(result + "2");
    },
    error => {
      console.log(error + ":2");
    }
  );
// reject1, Error: reject1:2
ログイン後にコピー

如果使用 .catch 方法,代码会简化很多,这样实际上是延长了 Promise 链

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("reject");
  }, 1000);
})
  .then(result => {
    console.log(result + "1");
    throw Error(result + "1"); // 抛出一个错误
  })
  .then(result => {
    console.log(result + "2");
    return Promise.resolve(result + "2");
  })
  .catch(err => {
    console.log(err);
  });
// reject1, Error: reject1:2
ログイン後にコピー

Promise.prototype.finally()

暂未完全成为标准的一部分,处于:Stage 4

finally() 方法返回一个 Promise,在执行 then() 和 catch() 后,都会执行finally指定的回调函数。(回调函数中无参数,仅仅代表 Promise 的已经结束

等同于使用 .then + .catch 延长了原有的 Promise 链的效果,避免同样的语句需要在 then() 和 catch() 中各写一次的情况。

mdn-Promise-finally

Promise 对象上的方法

Promise.all() 用来处理 Promise 的并发

Promise.all 会将多个 Promise 实例封装成一个新的 Promise 实例,新的 promise 的状态取决于多个 Promise 实例的状态,只有在全体 Promise 都为 fulfilled 的情况下,新的实例才会变成 fulfilled 状态。;如果参数中 Promise 有一个失败(rejected),此实例回调失败(rejecte),失败原因的是第一个失败 Promise 的结果。

举个例子:

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 3000, "p3");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// [p1,p2,p3]

Promise.all([
  new Promise(resolve => {
    setTimeout(resolve, 1000, "p1");
  }),
  new Promise(resolve => {
    setTimeout(resolve, 2000, "p2");
  }),
  Promise.reject("p3 error")
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error);
  });
// p3 error
ログイン後にコピー

获取 cnode 社区的 精华贴的前十条内容

fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10")
  .then(res => res.json())
  .then(res => {
    const fetchList = res.data.map(item => {
      return fetch(`https://cnodejs.org/api/v1/topic/${item.id}`)
        .then(res => res.json())
        .then(res => res.data);
    });
    Promise.all(fetchList).then(list => {
      console.log(list);
    });
  });
ログイン後にコピー

Promise.race() 竞态执行

Promise.race 也会将多个 Promise 实例封装成一个新的Promise实例,只不过新的 Promise 的状态取决于最先改变状态的 Promise 实例的状态。

在前端最典型的一个用法是为 fetch api 模拟请求超时。

Promise.race([
  fetch("https://cnodejs.org/api/v1/topics?tab=good&limit=10").then(res =>
    res.json()
  ),
  new Promise((resolve, reject) => {
    setTimeout(reject, 1, "error");
  })
])
  .then(result => {
    console.info("then", result);
  })
  .catch(error => {
    console.info("catch", error); // 进入这里
  });
ログイン後にコピー

上述例子中只要请求 未在 1 毫秒内结束就会进入 .catch() 方法中,虽然不能将请求取消,但是超时模拟却成功了

Promise.resolve(value) && Promise.reject(reason)

这两个方法都能用来创建并返回一个新的 Promise , 区别是 Promise.resolve(value) 携带进新的 Promise 状态是 fulfilled。而 Promise.reject(reason) 带来的 rejected

有的时候可以用来简化一些创建 Promise 的操作如:

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
// 这里创建一个 睡眠,并且打印的链
Promise.resolve()
  .then(() => {
    console.log(1);
  })
  .then(() => sleep(1000))
  .then(() => {
    console.log(2);
  })
  .then(() => sleep(2000))
  .then(() => {
    console.log(3);
  });
ログイン後にコピー

有时也用来 手动改变 Promise 链中的返回状态 ,当然这样实际上和 直接返回一个值,或者是 使用 throw Error 来构造一个错误,并无区别。到底要怎么用 就看个人喜好了

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("resolve"); // 1.
  }, 1000);
})
  .then(result => {
    return Promise.reject("reject1"); // 2.
  })
  .then(
    result => {
      return Promise.resolve(result + "2");
    },
    err => {
      return Promise.resolve(err); // 3.
    }
  )
  .then(res => {
    console.log(res); // 4.
  })
  .catch(err => {
    console.log(err + "err");
  });
// reject1
ログイン後にコピー

几个例子

下面来看几个例子:

关于执行顺序,具体可搜索,js 循环

new Promise((resolve, reject) => {
  console.log("step 1");
  resolve();
  console.log("step 2");
}).then(() => {
  console.log("step 3");
});
console.log("step 4");

// step 1, step 2, step 4 , step 3
ログイン後にコピー

在使用 Promise 构造函数构造 一个 Promise 时,回调函数中的内容就会立即执行,而 Promise.then 中的函数是异步执行的。

关于状态不可变更

let start;
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    start = Date.now();
    console.log("once");
    resolve("success");
  }, 1000);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
p.then(res => {
  console.log(res, Date.now() - start);
});
ログイン後にコピー

Promise 构造函数只执行一次,内部状态一旦改变,有了一个值,后续不论调用多少次then()都只拿到那么一个结果。

关于好像状态可以变更

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  }, 1000);
});

const p2 = p1.then((resolve, reject) => {
  throw new Error("error");
});

console.log("p1", p1);
console.log("p2", p2);

setTimeout(() => {
  console.log("p1", p1);
  console.log("p2", p2);
}, 2000);
ログイン後にコピー

观察这一次的打印
第一次打印出两个 Promise 的时候都是 pending ,因为 p2 是基于 p1 的结果,p1 正在 pending ,立即打印出的时候肯定是 pending ;第二次打印的时候,因为 p1 的状态为 resolved ,p2 为 rejected ,这个并不是已经为 fulfilled 状态改变为 rejected ,而是 p2 是一个新的 Promise 实例,then() 返回新的 Promise 实例。

关于透传

Promise.resolve(11)
  .then(1)
  .then(2)
  .then(3)
  .then(res => {
    console.info("res", res);
  });
//   11
ログイン後にコピー

给 then 方法传递了一个非函数的值,等同于 then(null),会导致穿透的效果,就是直接过掉了这个 then() ,直到符合规范的 then() 为止。

Promise 的串行调用

使用 Array.reduce 方法串行执行 Promise

const sleep = (time = 0) => new Promise(resolve => setTimeout(resolve, time));
[1000, 2000, 3000, 4000].reduce((Promise, item, index) => {
  return Promise.then(res => {
    console.log(index + 1);
    return sleep(item);
  });
}, Promise.resolve());
// 在分别的等待时间后输出 1,2,3,4
ログイン後にコピー

这篇文章到这里就基本上结束了,相信 如果能理解上面的内容,并且在实际项目中使用的话。应该会让工作更高效吧,对于新的异步使用应该也会更加的得心应手。Promise 的使用相对简单,可能后续再出一篇如何实现一个 Promise 吧。

以上が約束とは何ですか?約束の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

HTMLの表の境界線 HTMLの表の境界線 Sep 04, 2024 pm 04:49 PM

HTML の表の境界線に関するガイド。ここでは、HTML でのテーブルの境界線の例を示しながら、テーブル境界線を定義する複数の方法について説明します。

HTML 左マージン HTML 左マージン Sep 04, 2024 pm 04:48 PM

HTML マージン左のガイド。ここでは、HTML margin-left の概要とその例、およびそのコード実装について説明します。

HTML のネストされたテーブル HTML のネストされたテーブル Sep 04, 2024 pm 04:49 PM

これは、HTML でのネストされたテーブルのガイドです。ここでは、テーブル内にテーブルを作成する方法をそれぞれの例とともに説明します。

HTML テーブルのレイアウト HTML テーブルのレイアウト Sep 04, 2024 pm 04:54 PM

HTML テーブル レイアウトのガイド。ここでは、HTML テーブル レイアウトの値と例および出力について詳しく説明します。

HTML入力プレースホルダー HTML入力プレースホルダー Sep 04, 2024 pm 04:54 PM

HTML 入力プレースホルダーのガイド。ここでは、コードと出力とともに HTML 入力プレースホルダーの例について説明します。

HTML 順序付きリスト HTML 順序付きリスト Sep 04, 2024 pm 04:43 PM

HTML 順序付きリストのガイド。ここでは、HTML 順序付きリストと型の導入とその例についても説明します。

HTML 内のテキストの移動 HTML 内のテキストの移動 Sep 04, 2024 pm 04:45 PM

HTML でのテキストの移動に関するガイド。ここでは、概要、マーキー タグが構文でどのように機能するか、および実装例について説明します。

HTML の onclick ボタン HTML の onclick ボタン Sep 04, 2024 pm 04:49 PM

HTML オンクリック ボタンのガイド。ここでは、それらの紹介、動作、例、およびさまざまなイベントでの onclick イベントについてそれぞれ説明します。

See all articles