この記事の内容はPromiseとは何か? Promiseの紹介は参考になると思います。
実は、Promise の使用法については長い間書きたいと思っていました。 1 つは、実際のコーディングプロセスで頻繁に使用されること、もう 1 つは、友人が使用するときに時々問題が発生することです。
Promise は、ES6 の API 機能の 1 つであり、JS の記述方法に最も大きな影響を与えています。序文と基本概念
Promise は、従来のコールバック関数と比較して、複数のコールバックの深刻なネストの問題を解決します。
Promise オブジェクトは非同期操作を表し、保留中、完了済み、または拒否済みの 3 つの状態を持ちます。状態遷移は保留中、完了済み、保留中、拒否済みのいずれかになります。このプロセスは一度発生すると元に戻せません。 。
個人的には、Promise の説明は 2 つの部分に分ける必要があると考えています。
Promise コンストラクターの使用説明書。
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
を使用することもできます。指定するメソッドresolve
と reject
のコールバック関数
もエラーをキャッチする目的を達成できます。
request().then( result => { console.info(result); }, error => { console.info(error); } );
プロトタイプのメソッド
Promise.prototype.then()
p.then(onFulfilled, onRejected)
then メソッドは、上記の例のように、Promise.prototype で定義されたメソッドです。 2 つのパラメータ、満たされたコールバック関数と拒否されたコールバック関数。2 番目のパラメータはオプションです。
2 つの重要なポイント:
then メソッドの戻り値は新しい Promise
インスタンスであるため、呼び出し側は A ## を取得します。 #Promise オブジェクトは、
then を呼び出した後も
Promise を返し、その動作は then のコールバック関数の戻り値に関連します。次のように:
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); });
如上这个例子:两种方式在使用,与结果基本上是等价的,但是 仍然推荐第二种写法,下面我会给出原因:
在 Promise 链中 Promise.prototype.then(undefined, onRejected),onRejected 方法无法捕获当前 Promise 抛出的错误,而后续的 .catch 可以捕获之前的错误。
代码冗余
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 サイトの他の関連記事を参照してください。