Sự khác biệt giữa giá trị trả về hoặc Promise.resolve từ đó ()


314

Sự khác biệt giữa:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return "bbb";
  })
  .then(function(result) {
    console.log(result);
  });

và điều này:

new Promise(function(res, rej) {
    res("aaa");
  })
  .then(function(result) {
    return Promise.resolve("bbb");
  })
  .then(function(result) {
    console.log(result);
  });

Tôi đang hỏi khi tôi nhận được các hành vi khác nhau bằng cách sử dụng dịch vụ Angular và $ http với chuỗi .then (). Một chút quá nhiều mã do đó đầu tiên ví dụ ở trên.


1
"Hành vi khác nhau" bạn đang thấy là gì? Cả hai ví dụ nên hoạt động và hành xử gần như nhau. Trong Promise.resolve()ví dụ thứ hai là không cần thiết.
JLRishe

4
@pixelbits Không có gì sai khi trả lại lời hứa từ người thenxử lý, thực tế, đó là khía cạnh quan trọng của thông số hứa hẹn mà bạn có thể thực hiện.

Lưu ý rằng điều này hoạt động với thens được lồng tùy ý - thuật ngữ 'các ngôn ngữ khác' cho điều này thenlà cả a mapvà a flatMap.
Benjamin Gruenbaum

1
trong dòng 2 tại sao bạn phải gọi res ("aaa"), tại sao không thể trả lại "aaa" là đủ và hàm Promise bắt để giải quyết () giống như cách nó bắt ngoại lệ để từ chối ()?
Sam Liddicott

1
@SamLiddicott có cùng một câu hỏi, trong khi các mỏ phức tạp hơn một chút: new Promise((res, rej) => { return fetch('//google.com').then(() => { return "haha"; }) }).then((result) => alert(result));Mã này sẽ chỉ bị treo (không được giải quyết mãi mãi). Nhưng nếu tôi đổi return "haha";thành return res("haha");thì nó sẽ hoạt động và cảnh báo "haha". Không phải việc tìm nạp (). Sau đó () đã gói "haha" vào một lời hứa đã được giải quyết?
Shaung Cheng

Câu trả lời:


138

Quy tắc là, nếu hàm trong thentrình xử lý trả về một giá trị, thì lời hứa sẽ giải quyết / từ chối với giá trị đó và nếu hàm trả về một lời hứa, thì điều gì xảy ra, thenmệnh đề tiếp theo sẽ là thenmệnh đề của lời hứa mà hàm trả về , vì vậy, trong trường hợp này, ví dụ đầu tiên rơi vào chuỗi thông thường của các thensgiá trị và in ra các giá trị như người ta có thể mong đợi, trong ví dụ thứ hai, đối tượng lời hứa sẽ được trả về khi bạn thực hiện điều Promise.resolve("bbb")đó thenkhi được gọi khi xâu chuỗi (Cho mọi ý định và mục đích). Cách nó thực sự hoạt động được mô tả dưới đây chi tiết hơn.

Trích dẫn từ Promise / A + spec:

Thủ tục giải quyết lời hứa là một hoạt động trừu tượng lấy đầu vào là một lời hứa và một giá trị, mà chúng tôi biểu thị là [[Resolve]](promise, x). Nếu xlà một cái có thể, nó cố gắng thực hiện lời hứa thông qua trạng tháix , theo giả định rằng x hành xử ít nhất giống như một lời hứa . Nếu không, nó thực hiện lời hứa với giá trị x.

Cách xử lý này sau đó cho phép các triển khai hứa hẹn có thể tương tác với nhau, miễn là chúng đưa ra phương pháp Promise / A + -compliant sau đó. Nó cũng cho phép triển khai Promise / A + để đồng hóa các triển khai không phù hợp với các phương thức sau đó hợp lý.

Điều quan trọng cần chú ý ở đây là dòng này:

nếu xlà một lời hứa, chấp nhận trạng thái của nó [3,4]

liên kết: https://promisesaplus.com/#point-49


4
"Thông qua trạng thái của nó" là một cách ngắn gọn và hữu ích để thể hiện hành vi khi người thenxử lý trả lời hứa. +1 cho tham chiếu thông số kỹ thuật.

69
Trên thực tế - phần có liên quan của thông số kỹ thuật ở đây là thực tế [[Resolve]]được gọi là cả trên thenables và giá trị vì vậy về cơ bản, nó bao bọc một giá trị với lời hứa return "aaa"giống như return Promise.resolve("aaa")return Promise.resolve("aaa")giống như return Promise.resolve(Promise.resolve("aaa"))- vì giải quyết là bình thường gọi nó trên một giá trị nhiều hơn hơn một lần có kết quả tương tự
Benjamin Gruenbaum

8
@Benjamin Gruenbaum có nghĩa là sự trở lại "aaa"return Promise.resolve("aaa")có thể hoán đổi cho nhau trong thenables trong mọi trường hợp?
CSnerd

9
Vâng, đó chính xác là những gì nó có nghĩa.
Benjamin Gruenbaum

118

Nói một cách đơn giản, bên trong một thenhàm xử lý:

A) Khi nào xlà một giá trị (số, chuỗi, v.v.):

  1. return x tương đương với return Promise.resolve(x)
  2. throw x tương đương với return Promise.reject(x)

B) Khi nào xthì một Lời hứa đã được giải quyết (không chờ xử lý nữa):

  1. return xtương đương với return Promise.resolve(x), nếu Lời hứa đã được giải quyết.
  2. return xtương đương với return Promise.reject(x), nếu Lời hứa đã bị từ chối.

C) Khi nào xthì một Lời hứa đang chờ xử lý:

  1. return xsẽ trả lại một Lời hứa đang chờ xử lý và nó sẽ được đánh giá vào lần tiếp theo then.

Đọc thêm về chủ đề này trên các tài liệu Promise.prototype.then () .


93

Cả hai ví dụ của bạn nên cư xử khá giống nhau.

Giá trị được trả về bên trong bộ then()xử lý trở thành giá trị giải quyết của lời hứa được trả về từ đó then(). Nếu giá trị được trả lại bên trong .then là một lời hứa, thì lời hứa được trả lại then()sẽ "thông qua trạng thái" của lời hứa đó và giải quyết / từ chối giống như lời hứa được trả lại.

Trong ví dụ đầu tiên của bạn, bạn trở lại "bbb"trong then()trình xử lý đầu tiên , do đó "bbb"được chuyển sang then()trình xử lý tiếp theo .

Trong ví dụ thứ hai của bạn, bạn trả lại một lời hứa được giải quyết ngay lập tức với giá trị "bbb", do đó "bbb"được chuyển sang then()xử lý tiếp theo . (Ở Promise.resolve()đây là ngoại lai).

Kết quả là như nhau.

Nếu bạn có thể chỉ cho chúng tôi một ví dụ thực sự thể hiện hành vi khác nhau, chúng tôi có thể cho bạn biết lý do tại sao điều đó đang xảy ra.


1
Câu trả lời tốt đẹp! Thế còn Promise.resolve();vs return;?
FabianTe

2
@FabianTe Những người đó cũng sẽ có tác dụng tương tự, ngoại trừ undefinedthay vì "bbb".
JLRishe

51

Bạn đã có một câu trả lời chính thức tốt. Tôi hình dung tôi nên thêm một cái ngắn.

Những điều sau đây giống hệt với lời hứa / A + :

  • Gọi điện thoại Promise.resolve(Trong trường hợp Angular của bạn đó $q.when)
  • Gọi cho nhà xây dựng lời hứa và giải quyết trong trình giải quyết của nó. Trong trường hợp của bạn đó new $q.
  • Trả lại một giá trị từ một thencuộc gọi lại.
  • Gọi Promise.all trên một mảng có giá trị và sau đó trích xuất giá trị đó.

Vì vậy, những điều sau đây đều giống hệt nhau cho một lời hứa hoặc giá trị đơn giản X:

Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });

Và không có gì ngạc nhiên, đặc tả lời hứa dựa trên Quy trình giải quyết lời hứa cho phép tương tác dễ dàng giữa các thư viện (như $ q và lời hứa bản địa) và giúp cuộc sống của bạn dễ dàng hơn. Bất cứ khi nào một giải pháp lời hứa có thể xảy ra, một độ phân giải xảy ra tạo ra sự nhất quán tổng thể.


Tôi có thể hỏi những gì đang làm Promise.resolve().then(function(){ return x; });? Tôi tìm thấy một snipped làm một cái gì đó tương tự (nó được gọi là một chức năng bên trong thenkhối). Tôi nghĩ rằng nó ít nhiều giống như làm một khoảng thời gian chờ, nhưng nó nhanh hơn một chút. jsben.ch/HIfDo
Sampgun

Không có điểm nào giống như Promise.resolve (x) trong 99,99% trường hợp. (các 0,001% là chúng ta đang ở trong một withkhối trên một đối tượng hoặc proxy với một xaccessor tài sản đó ném một ngoại lệ. Trong trường hợp đó Promise.resolve (x) sẽ gây ra một lỗi ném nhưng Promise.resolve().then(function(){ return x; });sẽ là một lời hứa bị từ chối vì lỗi được ném trong một then)
Benjamin Gruenbaum

bạn đã liên kết một blitz trống, hoặc bạn đã không lưu. Dù sao tôi đã không nói về sự khác biệt giữa các tuyên bố. Tôi đã nói chính xác về những gì tôi đã viết. Nói rõ hơn, đây là đoạn tôi đã nói về : if (validator) { Promise.resolve().then(() => { this._cdRef.markForCheck(); }); }. Ở đây, lời hứa không được chỉ định, vậy vấn đề là gì? Một thời gian chờ sẽ có (ít nhiều) hiệu ứng tương tự, hay không?
Sampgun

1
Nó thực hiện cuộc gọi không đồng bộ sau khi tất cả các mã đồng bộ đã xảy ra nhưng trước khi bất kỳ I / O nào xảy ra. Đó gọi là "ngữ nghĩa microtick".
Benjamin Gruenbaum

1

Sự khác biệt duy nhất là bạn đang tạo ra một lời hứa không cần thiết khi bạn thực hiện return Promise.resolve("bbb"). Trả lại một lời hứa từ một người onFulfilled()xử lý khởi động giải quyết lời hứa . Đó là cách hứa hẹn hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.