[ES6] ルアン・イーフェン ES6 学習の約束 (1)

1. 意味

約束は非同期プログラミングの解決策

1.コンセプト

簡単に言うと、将来終了するイベント (通常は非同期操作) の結果を保持するコンテナーです。構文的には、Promise非同期操作のメッセージを取得できるオブジェクト。Promise統合された を提供しAPI、あらゆる種類の非同期操作を同じ方法で処理できます。

非同期プログラミング: fs ファイル操作、データベース操作、Ajax、タイマー;

2. 特長

  1. オブジェクトの状態は外界の影響を受けません。Promise オブジェクトは 3 つの状態を持つ非同期操作を表します

    • 保留中: 進行中
    • 満たされました: 成功しました
    • 拒否されました: 失敗しました

    非同期操作の結果のみが現在の状態を決定でき、他の操作はこの状態を変更できません。

  2. 一度状態が変化すると再度変化することはなく、いつでもこの結果が得られます。状態変化には、pendingへの変化fulfilledと へのpending変化の2 つの状態しかありませんrejected

3. 基本的な使い方

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

// Promise构造函数接受一个函数(执行器函数)作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
const promise = new Promise(function(resolve, reject) {
    
    
  // ... some code

  if (/* 异步操作成功 */){
    
    
  // 在异步操作成功时调用,并将异步操作的结果,作为参数value传递出去;
    resolve(value);
  } else {
    
    
  // 在异步操作失败时调用,并将异步操作报出的错误,作为参数error/reason传递出去。
    reject(error);
  }
});

Promise インスタンスが生成された後、 then メソッドを使用して、解決された状態と拒否された状態のコールバック関数をそれぞれ指定できます。

promise.then(function(value) {
    
    
  // success
}, function(error) {
    
    
  // failure
});

thenメソッドは 2 つのコールバック関数をパラメータとして受け入れることができます。

  • 最初のコールバック関数は、Promiseオブジェクトの状態が変化したresolvedときに呼び出されます。
  • 2 番目のコールバック関数は、Promiseオブジェクトの状態が変化したときに呼び出されますrejected

どちらの関数もオプションであり、必ず指定する必要はありません。これらはすべて、Promiseオブジェクトから渡された値をパラメータとして受け入れます。

// 创建一个新的p对象promise
const p = new Promise((resolve, reject) => {
    
     // 执行器函数
  // 执行异步操作任务
  setTimeout(() => {
    
    
    const time = Date.now() 
    // 如果当前时间是偶数代表成功,否则失败
    if (time % 2 == 0) {
    
    
      // 如果成功,调用resolve(value)
      resolve('成功的数据,time=' + time)
    } else {
    
    
      // 如果失败,调用reject(reason)
      reject('失败的数据,time=' + time)
    }
  }, 1000);
})

p.then(
  value => {
    
     // 接收得到成功的value数据 onResolved
    console.log('成功的回调', value)  // 成功的回调 成功的数据,time=1615015043258
  },
  reason => {
    
     // 接收得到失败的reason数据 onRejected
    console.log('失败的回调', reason)    // 失败的回调 失败的数据,time=1615014995315
  }
)

4. Promise を使用する理由

1. コールバック関数の指定方法がより柔軟になりました

旧: 非同期タスクを開始する前に指定する必要があります

// 1. 纯回调的形式
// 成功的回调函数
function successCallback(result) {
    
    
  console.log("声音文件创建成功:" + result);
}
// 失败的回调函数
function failureCallback(error) {
    
    
  console.log("声音文件创建失败:" + error);
}
// 必须先指定回调函数,再执行异步任务
createAudioFileAsync(audioSettings, successCallback, failureCallback) // 回调函数在执行异步任务(函数)前就要指定

Promise: 非同期タスクを開始する => Promise オブジェクトを返す => コー​​ルバック関数を Promise オブジェクトにバインドする (非同期タスクの終了後に指定することも可能)

// 2. 使用Promise
const promise = createAudioFileAsync(audioSettings);  // 执行2秒
setTimeout(() => {
    
    
  promise.then(successCallback, failureCallback) // 也可以获取
}, 3000);

2. コールバック地獄の問題を解決できるチェーンコールをサポートします。

コールバック 地獄: コールバック関数はネストされており、外側のコールバック関数の非同期実行の結果が、内側のネストされたコールバック関数の実行条件となります。

doSomething(function(result) {
    
    
  doSomethingElse(result, function(newResult) {
    
    
    doThirdThing(newResult, function(finalResult) {
    
    
      console.log('Got the final result:' + finalResult)
    }, failureCallback)
  }, failureCallback)
}, failureCallback)

promise連鎖呼び出しによるコールバック地獄の解決

doSomething()
  .then(result => doSomethingElse(result))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => {
    
    console.log('Got the final result:' + finalResult)})
  .catch(failureCallback)

Promise を使用した Ajax の実装

const getJSON = function(url) {
    
    
  const promise = new Promise(function(resolve, reject){
    
    
    const handler = function() {
    
    
      if (this.readyState !== 4) {
    
    
        return;
      }
      if (this.status === 200) {
    
    
        resolve(this.response);
      } else {
    
    
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
    
    
  console.log('Contents: ' + json);
}, function(error) {
    
    
  console.error('出错了', error);
});

上記のコードでは、getJSON は XMLHttpRequest オブジェクトのカプセル化であり、JSON データの HTTP リクエストを発行し、Promise オブジェクトを返すために使用されます。getJSON 内では、resolve 関数と拒否関数の両方がパラメーターを使用して呼び出されることに注意してください。

2番目に、Promiseの使用

1. Promise コンストラクター: Promise(executor) {}

  • エグゼキューター関数:同期実行(解決、拒否) => {}
  • solve 関数: 内部定義が成功したときに呼び出される関数solve(value)
  • 拒否関数: 内部定義が失敗したときに呼び出される関数拒否(reason)

説明: エグゼキュータはエグゼキュータであり、Promise 内で同期的に直ちにコールバックされ、非同期操作の解決/拒否がエグゼキュータで実行されます。

2. Promise.prototype.then 方法: (onResolved, onRejected) => {}

指定两个回调(成功+失败)

(1)onResolved関数: 成功コールバック関数(value) => {}

(2)onRejected関数:失敗時コールバック関数(reason) => {}

説明:value成功の場合は成功コールバック、reason 失敗の場合は失敗コールバックを指定し、新しいpromiseオブジェクトを返します。

2、Promise.prototype.catch 方法: p.(onRejected) => {}

失敗時のコールバックを指定する

(1) onRejected 関数: 失敗したコールバック関数 (理由) => {}

説明: これはthen()糖衣構文であり、以下と同等です。then(undefined, onRejected)

new Promise((resolve, reject) => {
    
     // excutor执行器函数
	 setTimeout(() => {
    
    
	   if(...) {
    
    
	     resolve('成功的数据') // resolve()函数
	   } else {
    
     
	     reject('失败的数据') //reject()函数
	    }
	 }, 1000)
}).then(
	 value => {
    
     // onResolved()函数
	 console.log(value) // 成功的数据
}).catch(
	 reason => {
    
     // onRejected()函数
	  console.log(reason) // 失败的数据
	}
)

3. Promise.resolve 方法: Promise.resolve(value) => {}

成功/失敗promiseオブジェクトを返します。

value: 成功データまたはpromiseオブジェクト

1. 受信パラメータが非 Promise タイプのオブジェクトである場合、返される結果は成功した Promise オブジェクトです

let p1 = Promise.resolve(521);
console.log(p1); // Promise {<fulfilled>: 521}

ここに画像の説明を挿入
2. 受信パラメータがPromiseオブジェクトの場合、パラメータの結果によって次resolveの結果が決まります。

let p2 = Promise.resolve(new Promise((resolve, reject) => {
    
    
    // resolve('OK'); // 成功的Promise
    reject('Error');
}));
console.log(p2);
p2.catch(reason => {
    
    
    console.log(reason);
})

ここに画像の説明を挿入

4. Promise.reject 方法: Promise.resolve(reason) => {}

(1) reason: 失敗の理由

説明: 失敗したpromiseオブジェクトを返します。

let p = Promise.reject(521);
let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
    
    
    resolve('OK');
}));

console.log(p);
console.log(p2);
console.log(p3);

ここに画像の説明を挿入
Promise.resolve()/Promise.reject()メソッドは、Promise オブジェクトをすばやく取得するための糖衣構文です。

5. Promise.all 方法: Promise.all(iterable) => {}

  • iterable: n を含むpromise反復可能なオブジェクト( またはArrayなど)String
  • promiseすべてが成功した場合にのみpromise成功し、1 つが失敗した場合は直接失敗する新しいものを返します。
let p1 = new Promise((resolve, reject) => {
    
    
  resolve('OK');
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');

const result = Promise.all([p1, p2, p3]);
console.log(result);

ここに画像の説明を挿入

let p1 = new Promise((resolve, reject) => {
    
    
  resolve('OK');
})
let p2 = Promise.reject('Error');
let p3 = Promise.resolve('Oh Yeah');

const result = Promise.all([p1, p2, p3]);
console.log(result);

ここに画像の説明を挿入

const p1 = Promise.resolve(1)
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)

const pAll = Promise.all([p1, p2, p3])
const pAll2 = Promise.all([p1, p2])
//因为其中p3是失败所以pAll失败
pAll.then(
value => {
    
    
   console.log('all onResolved()', value)
 },
reason => {
    
    
   console.log('all onRejected()', reason) 
 }
)
// all onRejected() 3
pAll2.then(
values => {
    
    
   console.log('all onResolved()', values)
 },
reason => {
    
    
   console.log('all onRejected()', reason) 
 }
)
// all onResolved() [1, 2]

7. Promise.race方法:Promise.race(iterable) => {}

  • iterable: n を含むpromise反復可能なオブジェクト( またはArrayなど)String
  • 新しいpromise、最初に完了したpromise結果状態、つまり最終結果状態を返します。
const pRace = Promise.race([p1, p2, p3])
// 谁先完成就输出谁(不管是成功还是失败)
const p1 = new Promise((resolve, reject) => {
    
    
 setTimeout(() => {
    
    
   resolve(1)
 }, 1000)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)

pRace.then(
value => {
    
    
   console.log('race onResolved()', value)
 },
reason => {
    
    
   console.log('race onRejected()', reason) 
 }
)
//race onResolved() 2
let p1 = new Promise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
      resolve('OK');
  }, 1000);
})
let p2 = Promise.resolve('Success');
let p3 = Promise.resolve('Oh Yeah');

//调用
const result = Promise.race([p1, p2, p3]);

console.log(result);

ここに画像の説明を挿入

3. いくつかの重要な約束事項

1. プロミスの状態を変更するにはどうすればよいですか?

(1) resolve(value): 現在の場合は次pendingのようになりますresolved

(2) reject(reason): 現在の場合はpending`rejected` になります

(3) 例外をスローする: 現在の場合、次 pendingのようになります。rejected

const p = new Promise((resolve, reject) => {
    
    
  //resolve(1) // promise变为resolved成功状态
  //reject(2) // promise变为rejected失败状态
  throw new Error('出错了') // 抛出异常,promise变为rejected失败状态,reason为抛出的error
})
p.then(
  value => {
    
    },
  reason => {
    
    console.log('reason',reason)}
)
// reason Error:出错了

2. Promise で複数の成功/失敗コールバック関数が指定されていますが、それらはすべて呼び出されますか?

Promise が対応する状態に変化したときに呼び出されます

const p = new Promise((resolve, reject) => {
    
    
  //resolve(1)
  reject(2)
})
p.then(
  value => {
    
    },
  reason => {
    
    console.log('reason',reason)}
)
p.then(
  value => {
    
    },
  reason => {
    
    console.log('reason2',reason)}
)
// reason 2
// reason2 2

3. Promise の状態を変更し、コールバック関数を指定するのはどれが最初でしょうか?

(1) どちらも可能 通常はコールバックを指定して状態を変更しますが、状態を変更してからコールバックを指定することも可能です

(2) 最初に状態を変更してからコールバックを指定するにはどうすればよいですか?

①executor内でresolve()/reject()を直接呼び出す

② then()を呼び出すまでの時間を長くする

let p = new Promise((resolve, reject) => {
    
    
  // setTimeout(() => {
    
    
      resolve('OK');
  // }, 1000); // 有异步就先指定回调,否则先改变状态
});

p.then(value => {
    
    
  console.log(value);
},reason=>{
    
    
  
})

(3) データはいつ入手可能になりますか?

①最初にコールバックを指定すると、状態が変化したときにコールバック関数が呼び出されてデータを取得します。

②先に状態を変更した場合、コールバックを指定するとコールバック関数が呼び出されてデータを取得します。

new Promise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
    resolve(1) // 改变状态
  }, 1000)
}).then( // 指定回调函数 (先指定)
  value => {
    
    },
  reason =>{
    
    }
)

この時点で、最初にコールバック関数を指定し、現在指定されているコールバック関数を保存し、次に状態を変更し (データを指定しながら)、以前に保存したコールバック関数を非同期に実行します。

new Promise((resolve, reject) => {
    
    
  resolve(1) // 改变状态
}).then( // 指定回调函数
  value => {
    
    },
  reason =>{
    
    }
)

この書き方は、まず状態を変更(同時にデータを指定)し、次にコールバック関数を指定(再度保存する必要はありません)し、コールバック関数を非同期で直接実行します。

4.promise.then() によって返される新しい Promise の結果の状態は何によって決まりますか?

(1) 単純な式:then()で指定したコールバック関数の実行結果により決定

let p = new Promise((resolve, reject) => {
    
    
  resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
    
    
  console.log(value);
}, reason => {
    
    
  console.warn(reason);
});

console.log(result);

ここに画像の説明を挿入

(2) 詳細表現:

① 例外がスローされた場合、新しい Promise は拒否されます。理由はスローされた例外です。

let p = new Promise((resolve, reject) => {
    
    
  resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
    
    
  //1. 抛出错误
  throw '出了问题';
}, reason => {
    
    
  console.warn(reason);
});

console.log(result);

ここに画像の説明を挿入
② Promise 以外の値が返された場合、新しい Promise は解決され、value は戻り値になります。

let p = new Promise((resolve, reject) => {
    
    
  resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
    
    
	//2. 返回结果是非 Promise 类型的对象
	return 521;
}, reason => {
    
    
  console.warn(reason);
});

console.log(result);

ここに画像の説明を挿入

③ 別の新しいPromiseが返された場合、このPromiseの結果は新しいPromiseの結果になります

let p = new Promise((resolve, reject) => {
    
    
  resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
    
    
	//3. 返回结果是 Promise 对象
	return new Promise((resolve, reject) => {
    
    
		// resolve('success');
		reject('error');
	});
}, reason => {
    
    
  console.warn(reason);
});

console.log(result);

ここに画像の説明を挿入

new Promise((resolve, reject) => {
    
    
  resolve(1)
}).then(
  value => {
    
    
    console.log('onResolved1()', value)
  },
  reason => {
    
    
    console.log('onRejected1()', reason)
  }
).then(
  value => {
    
    
    console.log('onResolved2()', value)
  },
  reason => {
    
    
    console.log('onRejected2()', reason)
  }
)
// onResolved1() 1
// onResolved2() undefined
new Promise((resolve, reject) => {
    
    
  resolve(1)
}).then(
  value => {
    
    
    console.log('onResolved1()', value)
    //return 2                   // onResolved2() 2
    //return Promise.resolve(3)  // onResolved2() 3
    //return Promise.reject(4)   // onRejected2() 4
    //throw 5                    // onRejected2() 5
  },
  reason => {
    
    
    console.log('onRejected1()', reason)
  }
).then(
  value => {
    
    
    console.log('onResolved2()', value)
  },
  reason => {
    
    
    console.log('onRejected2()', reason)
  }
)
// onResolved1() 1
// onResolved2() undefined
// Promise {<fulfilled>: undefined}
// 对应输出如上所示

5. Promise は複数の操作タスクをどのように連鎖させますか?

(1)開くことができる新しいチェーン コールpromiseを返します。then()promisethen()

(2)then複数の同期・非同期タスクをチェーンコールで直列に接続

let p = new Promise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
      resolve('OK');
  }, 1000);
});

p.then(value => {
    
    
  return new Promise((resolve, reject) => {
    
    
      resolve("success");
  });
}).then(value => {
    
    
  console.log(value); // success
}).then(value => {
    
    
  console.log(value); // undefined
})
new Promise((resolve, reject) => {
    
    
  setTimeout(() => {
    
    
    console.log('执行任务1(异步)')
    resolve(1)
  }, 1000)
}).then(
  value => {
    
    
    console.log('任务1的结果', value)
    console.log('执行任务2(同步)')
    return 2 // 同步任务直接return返回结果
  }
).then(
  value => {
    
    
    console.log('任务2的结果', value)
    return new Promise((resolve, reject) => {
    
     // 异步任务需要包裹在Promise对象中
      setTimeout(() => {
    
    
        console.log('执行任务3(异步)')
        resolve(3)
      }, 1000)
    })
  }
).then(
  value => {
    
    
    console.log('任务3的结果', value)
  }
)
// 执行任务1(异步)
// 任务1的结果 1
// 执行任务2(同步)
// 任务2的结果 2
// 执行任务3(异步)
// 任务3的结果 3

6. 約束の連鎖を断ち切る?

(1) のチェーンコールを使用すると途中promise then中断され、後続のコールバック関数が呼び出されなくなります

(2) 方法:コールバック関数でpendding状態promiseオブジェクトを返す

new Promise((resolve, reject) => {
    
    
   //resolve(1)
   reject(1)
}).then(
  value => {
    
    
    console.log('onResolved1()', value)
    return 2
  }
).then(
  value => {
    
    
    console.log('onResolved2()', value)
    return 3
  }
).then(
  value => {
    
    
    console.log('onResolved3()', value)
  }
).catch(
  reason => {
    
    
    console.log('onRejected1()', reason)
  }
).then(
  value => {
    
    
    console.log('onResolved4()', value)
  },
  reason => {
    
    
    console.log('onRejected2()', reason)
  }
)
// onRejected1() 1
// onResolved4() undefined

おすすめ

転載: blog.csdn.net/Bon_nenul/article/details/128224182