Url cuộc gọi javascript

Một

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
2 là một đối tượng đại diện cho việc hoàn thành hoặc thất bại cuối cùng của một hoạt động không đồng bộ. Vì hầu hết mọi người là người tiêu dùng của những lời hứa đã được tạo, hướng dẫn này sẽ giải thích việc tiêu thụ những lời hứa được trả lại trước khi giải thích cách tạo chúng

Về cơ bản, một lời hứa là một đối tượng được trả về mà bạn đính kèm các cuộc gọi lại, thay vì chuyển các cuộc gọi lại vào một hàm. Hãy tưởng tượng một chức năng,

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
3, tạo ra một tệp âm thanh không đồng bộ với một bản ghi cấu hình và hai chức năng gọi lại. một được gọi nếu tệp âm thanh được tạo thành công và một được gọi nếu xảy ra lỗi

Đây là một số mã sử dụng

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
3

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);

Nếu

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
3 được viết lại để trả lại một lời hứa, thay vào đó, bạn sẽ đính kèm các lệnh gọi lại của mình vào đó

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

Quy ước này có một số lợi thế. Chúng ta sẽ khám phá từng cái một

xiềng xích

Một nhu cầu phổ biến là thực hiện hai hoặc nhiều hoạt động không đồng bộ quay lại, trong đó mỗi hoạt động tiếp theo bắt đầu khi hoạt động trước đó thành công, với kết quả từ bước trước đó. Ngày xưa, thực hiện một số hoạt động không đồng bộ liên tiếp sẽ dẫn đến kim tự tháp gọi lại cổ điển của sự diệt vong

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

Với những lời hứa, chúng tôi thực hiện điều này bằng cách tạo một chuỗi lời hứa. Thiết kế API của các lời hứa làm cho điều này trở nên tuyệt vời, bởi vì các cuộc gọi lại được đính kèm với đối tượng lời hứa được trả về, thay vì được chuyển vào một hàm

Đây là điều kỳ diệu. hàm

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
6 trả về một lời hứa mới, khác với lời hứa ban đầu

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);

Lời hứa thứ hai này (

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
7) thể hiện sự hoàn thành không chỉ của
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
8, mà còn của
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
9 hoặc
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
20 mà bạn đã chuyển vào — có thể là các hàm không đồng bộ khác trả về một lời hứa. Trong trường hợp đó, bất kỳ cuộc gọi lại nào được thêm vào
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
7 sẽ được xếp hàng sau lời hứa được trả về bởi
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
9 hoặc
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
20

Với mẫu này, bạn có thể tạo các chuỗi xử lý dài hơn, trong đó mỗi lời hứa thể hiện việc hoàn thành một bước không đồng bộ trong chuỗi. Ngoài ra, các đối số của

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
24 là tùy chọn và
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
25 là viết tắt của
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
26 — vì vậy nếu mã xử lý lỗi của bạn giống nhau cho tất cả các bước, bạn có thể đính kèm mã đó vào cuối chuỗi

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
2

Thay vào đó, bạn có thể thấy điều này được thể hiện bằng các hàm mũi tên

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
0

Quan trọng. Luôn trả về kết quả, nếu không, các cuộc gọi lại sẽ không bắt được kết quả của lời hứa trước đó (với các chức năng mũi tên,

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
27 là viết tắt của
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
28). Nếu người xử lý trước đó đã bắt đầu một lời hứa nhưng không trả lại, thì không có cách nào để theo dõi việc giải quyết của nó nữa và lời hứa được cho là "thả nổi"

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
3

Điều này có thể tồi tệ hơn nếu bạn có điều kiện chủng tộc — nếu lời hứa từ trình xử lý cuối cùng không được trả lại, trình xử lý

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
24 tiếp theo sẽ được gọi sớm và mọi giá trị mà nó đọc có thể không đầy đủ

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
5

Do đó, theo nguyên tắc thông thường, bất cứ khi nào hoạt động của bạn gặp phải một lời hứa, hãy trả lại nó và hoãn việc xử lý nó cho trình xử lý

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
24 tiếp theo

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
7

làm tổ

Trong hai ví dụ trên, ví dụ đầu tiên có một chuỗi lời hứa được lồng trong giá trị trả về của một trình xử lý

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
6 khác, trong khi ví dụ thứ hai sử dụng một chuỗi phẳng hoàn toàn. Các chuỗi lời hứa đơn giản tốt nhất nên được giữ phẳng mà không cần lồng vào nhau, vì việc lồng vào nhau có thể là kết quả của thành phần bất cẩn. Xem những lỗi thường gặp

Nesting là một cấu trúc điều khiển để giới hạn phạm vi của các câu lệnh

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02. Cụ thể, một
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02 lồng nhau chỉ phát hiện lỗi trong phạm vi của nó và bên dưới, không phát hiện lỗi cao hơn trong chuỗi bên ngoài phạm vi lồng nhau. Khi được sử dụng đúng cách, điều này mang lại độ chính xác cao hơn trong việc khôi phục lỗi

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
1

Lưu ý rằng các bước tùy chọn ở đây được lồng vào nhau — với việc lồng vào nhau không phải do vết lõm, mà do vị trí của dấu ngoặc đơn

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
04 và
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
05 bên ngoài xung quanh các bước

Trình xử lý tắt tiếng lỗi bên trong

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02 chỉ phát hiện lỗi từ
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
07 và
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
08, sau đó mã sẽ tiếp tục với
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
09. Điều quan trọng là, nếu
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
30 không thành công, lỗi của nó chỉ được phát hiện bởi
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02 cuối cùng (bên ngoài) và không bị nuốt bởi trình xử lý
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02 bên trong

Chuỗi sau khi bắt

Có thể xâu chuỗi sau một thất bại, tôi. e. một

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02, rất hữu ích để hoàn thành các hành động mới ngay cả sau khi một hành động không thành công trong chuỗi. Đọc ví dụ sau

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
0

Điều này sẽ xuất văn bản sau

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
1

Ghi chú. Văn bản "Làm điều này" không được hiển thị vì lỗi "Đã xảy ra lỗi" khiến từ chối

Lỗi thường gặp

Dưới đây là một số lỗi phổ biến cần chú ý khi soạn chuỗi lời hứa. Một số trong những sai lầm này biểu hiện trong ví dụ sau

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
2

Sai lầm đầu tiên là không xâu chuỗi mọi thứ lại với nhau đúng cách. Điều này xảy ra khi chúng tôi tạo một lời hứa mới nhưng quên trả lại nó. Kết quả là chuỗi bị hỏng — hay đúng hơn là chúng ta có hai chuỗi độc lập chạy đua với nhau. Điều này có nghĩa là

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
34 sẽ không đợi
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
35 hoặc
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
36 kết thúc mà sẽ chạy song song với chúng — điều này có thể xảy ra ngoài ý muốn. Các chuỗi riêng biệt cũng có cách xử lý lỗi riêng biệt, dẫn đến các lỗi không được phát hiện

Sai lầm thứ hai là lồng vào nhau một cách không cần thiết, tạo điều kiện cho sai lầm đầu tiên. Việc lồng ghép cũng giới hạn phạm vi của trình xử lý lỗi bên trong, mà—nếu ngoài ý muốn—có thể dẫn đến các lỗi chưa được phát hiện. Một biến thể của điều này là mẫu chống lại hàm tạo lời hứa, kết hợp việc lồng với việc sử dụng dự phòng của hàm tạo lời hứa để bọc mã đã sử dụng lời hứa

Sai lầm thứ ba là quên kết thúc chuỗi với

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
02. Chuỗi lời hứa chưa được kết thúc dẫn đến việc từ chối lời hứa chưa được thực hiện trong hầu hết các trình duyệt. Xem xử lý lỗi bên dưới

Một nguyên tắc nhỏ là luôn trả lại hoặc chấm dứt chuỗi lời hứa và ngay khi bạn nhận được một lời hứa mới, hãy trả lại nó ngay lập tức để làm phẳng mọi thứ

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
3

Lưu ý rằng

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
27 là viết tắt của
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
28

Bây giờ chúng tôi có một chuỗi xác định duy nhất với việc xử lý lỗi thích hợp

Sử dụng

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
50/
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51 giải quyết hầu hết, nếu không muốn nói là tất cả những vấn đề này — sự đánh đổi là có thể dễ dàng quên từ khóa
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51

xử lý lỗi

Bạn có thể nhớ đã nhìn thấy

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
20 ba lần trong kim tự tháp diệt vong trước đó, so với chỉ một lần ở cuối chuỗi lời hứa

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
4

Nếu có ngoại lệ, trình duyệt sẽ tìm xuống chuỗi để tìm trình xử lý

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
54 hoặc
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
55. Điều này được mô hình hóa rất nhiều sau cách thức hoạt động của mã đồng bộ

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
5

Sự đối xứng này với mã không đồng bộ lên đến đỉnh điểm trong cú pháp

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
50/
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
6

Nó được xây dựng dựa trên các lời hứa — ví dụ,

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
8 vẫn giữ nguyên chức năng như trước đây, do đó, chỉ cần tái cấu trúc tối thiểu để thay đổi từ các lời hứa thành
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
50/
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51. Bạn có thể đọc thêm về cú pháp
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
50/
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51 trong các hàm async và tài liệu tham khảo
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
51

Lời hứa giải quyết một lỗ hổng cơ bản với kim tự tháp gọi lại của sự diệt vong, bằng cách bắt tất cả các lỗi, thậm chí cả các ngoại lệ bị ném và lỗi lập trình. Điều này là cần thiết cho thành phần chức năng của các hoạt động không đồng bộ

Sự kiện từ chối lời hứa

Nếu một sự kiện từ chối lời hứa không được xử lý bởi bất kỳ trình xử lý nào, nó sẽ nổi lên trên cùng của ngăn xếp cuộc gọi và máy chủ lưu trữ cần hiển thị nó. Trên web, bất cứ khi nào một lời hứa bị từ chối, một trong hai sự kiện sẽ được gửi đến phạm vi toàn cầu (thông thường, đây là

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
74 hoặc, nếu được sử dụng trong nhân viên web, đó là
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
75 hoặc giao diện dựa trên nhân viên khác). Hai sự kiện là

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
76

Được gửi khi một lời hứa bị từ chối nhưng không có sẵn trình xử lý từ chối

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
77

Được gửi khi một trình xử lý được đính kèm với một lời hứa bị từ chối đã gây ra sự kiện

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
76

Trong cả hai trường hợp, sự kiện (thuộc loại

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
79) có các thành viên thuộc tính
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
10 cho biết lời hứa đã bị từ chối và thuộc tính
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
11 cung cấp lý do cho lời hứa bị từ chối

Những điều này có thể cung cấp khả năng xử lý lỗi dự phòng cho các lời hứa, cũng như giúp gỡ lỗi các vấn đề với quản lý lời hứa của bạn. Các trình xử lý này là toàn cầu theo ngữ cảnh, vì vậy tất cả các lỗi sẽ chuyển đến cùng một trình xử lý sự kiện, bất kể nguồn

trong nút. js, việc xử lý từ chối lời hứa hơi khác một chút. Bạn nắm bắt các từ chối chưa được xử lý bằng cách thêm trình xử lý cho Nút. js sự kiện

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
12 (chú ý sự khác biệt trong cách viết hoa của tên), như thế này

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
7

Đối với nút. js, để ngăn lỗi được ghi vào bảng điều khiển (hành động mặc định sẽ xảy ra), việc thêm trình nghe

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
13 đó là tất cả những gì cần thiết;

Tuy nhiên, nếu bạn thêm trình nghe

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
15 đó nhưng cũng không có mã bên trong để xử lý các lời hứa bị từ chối, chúng sẽ bị loại bỏ và bị bỏ qua một cách im lặng. Vì vậy, lý tưởng nhất là bạn nên thêm mã trong trình nghe đó để kiểm tra từng lời hứa bị từ chối và đảm bảo rằng nó không phải do lỗi mã thực sự gây ra

Thành phần

Có bốn công cụ tổng hợp để chạy đồng thời các hoạt động không đồng bộ.

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
16,
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
17,
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
18 và
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
19

Chúng ta có thể bắt đầu hoạt động song song và đợi tất cả chúng kết thúc như thế này

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
8

Nếu một trong những lời hứa trong mảng bị từ chối,

function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
16 ngay lập tức từ chối lời hứa được trả lại và hủy bỏ các hoạt động khác. Điều này có thể gây ra trạng thái hoặc hành vi không mong muốn.
function successCallback(result) {
  console.log(`Audio file ready at URL: ${result}`);
}

function failureCallback(error) {
  console.error(`Error generating audio file: ${error}`);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
17 là một công cụ tổng hợp khác đảm bảo tất cả các hoạt động được hoàn thành trước khi giải quyết

Tất cả các phương thức này đều chạy song song các lời hứa — một chuỗi các lời hứa được bắt đầu đồng thời và không đợi nhau. Thành phần tuần tự có thể sử dụng một số JavaScript thông minh

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
9

Trong ví dụ này, chúng tôi rút gọn một mảng các hàm không đồng bộ thành một chuỗi lời hứa. Đoạn mã trên tương đương với

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
0

Điều này có thể được tạo thành một chức năng soạn thảo có thể tái sử dụng, phổ biến trong lập trình chức năng

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
1

Hàm

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
02 chấp nhận bất kỳ số lượng hàm nào làm đối số và trả về một hàm mới chấp nhận một giá trị ban đầu được chuyển qua đường ống thành phần

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
2

Bố cục tuần tự cũng có thể được thực hiện ngắn gọn hơn với async/await

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
3

Tuy nhiên, trước khi bạn soạn các lời hứa một cách tuần tự, hãy cân nhắc xem điều đó có thực sự cần thiết hay không — tốt hơn hết là chạy các lời hứa song song để chúng không chặn lẫn nhau một cách không cần thiết trừ khi việc thực hiện một lời hứa phụ thuộc vào kết quả của một lời hứa khác

Tạo một Lời hứa xung quanh API gọi lại cũ

Một

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
2 có thể được tạo từ đầu bằng hàm tạo của nó. Điều này chỉ cần thiết để bọc các API cũ

Trong một thế giới lý tưởng, tất cả các chức năng không đồng bộ sẽ trả về lời hứa. Thật không may, một số API vẫn mong đợi các cuộc gọi lại thành công và/hoặc thất bại được chuyển theo cách cũ. Ví dụ rõ ràng nhất là hàm

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
04

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
4

Trộn các cuộc gọi lại và lời hứa kiểu cũ là vấn đề. Nếu

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
05 bị lỗi hoặc có lỗi lập trình, không có gì bắt được nó. Đây là bản chất của thiết kế của
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
06

May mắn thay, chúng ta có thể gói gọn

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
06 trong một lời hứa. Cách tốt nhất là bọc các chức năng chấp nhận gọi lại ở mức thấp nhất có thể và sau đó không bao giờ gọi lại chúng trực tiếp nữa

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
5

Hàm tạo lời hứa có chức năng thực thi cho phép chúng tôi giải quyết hoặc từ chối lời hứa theo cách thủ công. Vì

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
04 không thực sự bị lỗi, chúng tôi đã loại bỏ từ chối trong trường hợp này. Để biết thêm thông tin về cách chức năng thực thi hoạt động, hãy xem tài liệu tham khảo
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
09

thời gian

Cuối cùng, chúng ta sẽ xem xét các chi tiết kỹ thuật hơn, về thời điểm cuộc gọi lại đã đăng ký được gọi

bảo lãnh

Trong API dựa trên gọi lại, thời điểm và cách thức gọi lại tùy thuộc vào trình triển khai API. Ví dụ: cuộc gọi lại có thể được gọi đồng bộ hoặc không đồng bộ

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
6

Điều này dẫn đến tình trạng của Zalgo, vì nó làm cho các tác dụng phụ khó phân tích

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
7

Mặt khác, các lời hứa là một dạng đảo ngược quyền kiểm soát - trình triển khai API không kiểm soát thời điểm cuộc gọi lại được gọi. Thay vào đó, công việc duy trì hàng đợi gọi lại và quyết định khi nào gọi các cuộc gọi lại được giao cho việc triển khai lời hứa và cả người dùng API và nhà phát triển API đều tự động nhận được các đảm bảo ngữ nghĩa mạnh mẽ, bao gồm

  • Các cuộc gọi lại được thêm bằng
    const promise = doSomething();
    const promise2 = promise.then(successCallback, failureCallback);
    
    6 sẽ không bao giờ được gọi trước khi hoàn thành vòng chạy sự kiện JavaScript hiện tại
  • Các cuộc gọi lại này sẽ được gọi ngay cả khi chúng được thêm vào sau thành công hay thất bại của hoạt động không đồng bộ mà lời hứa đại diện
  • Nhiều cuộc gọi lại có thể được thêm vào bằng cách gọi
    const promise = doSomething();
    const promise2 = promise.then(successCallback, failureCallback);
    
    6 nhiều lần. Chúng sẽ được gọi lần lượt, theo thứ tự mà chúng được chèn vào

Để tránh bất ngờ, các chức năng được chuyển đến

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
6 sẽ không bao giờ được gọi đồng bộ, ngay cả với một lời hứa đã được giải quyết

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
8

Thay vì chạy ngay lập tức, hàm truyền vào được đặt trong hàng đợi vi tác vụ, có nghĩa là nó chạy sau (chỉ sau khi hàm tạo ra nó thoát ra và khi ngăn xếp thực thi JavaScript trống), ngay trước khi quyền điều khiển được trả lại cho sự kiện . e. khá sớm

doSomething(function (result) {
  doSomethingElse(result, function (newResult) {
    doThirdThing(newResult, function (finalResult) {
      console.log(`Got the final result: ${finalResult}`);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
9

Hàng đợi nhiệm vụ so với vi nhiệm vụ

Các cuộc gọi lại lời hứa được xử lý dưới dạng một tác vụ nhỏ trong khi các cuộc gọi lại

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
04 được xử lý dưới dạng hàng đợi nhiệm vụ

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
0

Đoạn mã trên sẽ xuất ra

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
1

Để biết thêm chi tiết, hãy tham khảo Nhiệm vụ so với vi nhiệm vụ

Khi lời hứa và nhiệm vụ xung đột

Nếu bạn gặp phải các tình huống trong đó bạn có các lời hứa và nhiệm vụ (chẳng hạn như các sự kiện hoặc cuộc gọi lại) đang thực hiện theo thứ tự không thể đoán trước, bạn có thể hưởng lợi từ việc sử dụng một vi tác vụ để kiểm tra trạng thái hoặc cân bằng các lời hứa của mình khi các lời hứa được tạo ra một cách có điều kiện

Nếu bạn nghĩ rằng các tác vụ vi mô có thể giúp giải quyết vấn đề này, hãy xem hướng dẫn tác vụ vi mô để tìm hiểu thêm về cách sử dụng

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
14 để liệt kê một hàm dưới dạng một tác vụ vi mô