Ưu / nhược điểm của việc sử dụng redux-saga với máy phát ES6 so với redux-thunk với ES2017 async / await


488

Có rất nhiều cuộc nói chuyện về đứa trẻ mới nhất trong thị trấn redux ngay bây giờ, redux-saga / redux-saga . Nó sử dụng các chức năng của trình tạo để nghe / gửi các hành động.

Trước khi tôi xoay quanh nó, tôi muốn biết những ưu / nhược điểm của việc sử dụng redux-sagathay vì cách tiếp cận bên dưới nơi tôi đang sử dụng redux-thunkvới async / await.

Một thành phần có thể trông như thế này, gửi các hành động như bình thường.

import { login } from 'redux/auth';

class LoginForm extends Component {

  onClick(e) {
    e.preventDefault();
    const { user, pass } = this.refs;
    this.props.dispatch(login(user.value, pass.value));
  }

  render() {
    return (<div>
        <input type="text" ref="user" />
        <input type="password" ref="pass" />
        <button onClick={::this.onClick}>Sign In</button>
    </div>);
  } 
}

export default connect((state) => ({}))(LoginForm);

Sau đó, hành động của tôi trông giống như thế này:

// auth.js

import request from 'axios';
import { loadUserData } from './user';

// define constants
// define initial state
// export default reducer

export const login = (user, pass) => async (dispatch) => {
    try {
        dispatch({ type: LOGIN_REQUEST });
        let { data } = await request.post('/login', { user, pass });
        await dispatch(loadUserData(data.uid));
        dispatch({ type: LOGIN_SUCCESS, data });
    } catch(error) {
        dispatch({ type: LOGIN_ERROR, error });
    }
}

// more actions...

// user.js

import request from 'axios';

// define constants
// define initial state
// export default reducer

export const loadUserData = (uid) => async (dispatch) => {
    try {
        dispatch({ type: USERDATA_REQUEST });
        let { data } = await request.get(`/users/${uid}`);
        dispatch({ type: USERDATA_SUCCESS, data });
    } catch(error) {
        dispatch({ type: USERDATA_ERROR, error });
    }
}

// more actions...

6
Xem thêm câu trả lời của tôi so sánh redux-thunk với redux-saga tại đây: stackoverflow.com/a/34623840/82609
Sebastien Lorber

22
Là gì ::trước khi bạn this.onClicklàm?
Downhillski

37
@ZhenyangHua nó là một tay ngắn để ràng buộc hàm với đối tượng ( this), aka this.onClick = this.onClick.bind(this). Dạng dài hơn thường được khuyến nghị thực hiện trong hàm tạo, vì tay ngắn liên kết lại trên mỗi kết xuất.
hampusohlsson

7
Tôi hiểu rồi. cảm ơn! Tôi thấy mọi người sử dụng bind()rất nhiều để chuyển thisđến chức năng, nhưng tôi đã bắt đầu sử dụng () => method()ngay bây giờ.
Downhillski

2
@Hosar Tôi đã sử dụng redux & redux-saga trong sản xuất một thời gian, nhưng thực sự đã chuyển sang MobX sau một vài tháng vì ít chi phí hơn
hampusohlsson

Câu trả lời:


461

Trong redux-saga, tương đương với ví dụ trên sẽ là

export function* loginSaga() {
  while(true) {
    const { user, pass } = yield take(LOGIN_REQUEST)
    try {
      let { data } = yield call(request.post, '/login', { user, pass });
      yield fork(loadUserData, data.uid);
      yield put({ type: LOGIN_SUCCESS, data });
    } catch(error) {
      yield put({ type: LOGIN_ERROR, error });
    }  
  }
}

export function* loadUserData(uid) {
  try {
    yield put({ type: USERDATA_REQUEST });
    let { data } = yield call(request.get, `/users/${uid}`);
    yield put({ type: USERDATA_SUCCESS, data });
  } catch(error) {
    yield put({ type: USERDATA_ERROR, error });
  }
}

Điều đầu tiên cần lưu ý là chúng ta đang gọi các hàm api bằng biểu mẫu yield call(func, ...args). callkhông thực hiện hiệu ứng, nó chỉ tạo ra một đối tượng đơn giản như thế {type: 'CALL', func, args}. Việc thực thi được ủy quyền cho phần mềm trung gian redux-saga, đảm nhiệm việc thực thi chức năng và nối lại trình tạo với kết quả của nó.

Ưu điểm chính là bạn có thể kiểm tra trình tạo bên ngoài Redux bằng cách sử dụng kiểm tra đẳng thức đơn giản

const iterator = loginSaga()

assert.deepEqual(iterator.next().value, take(LOGIN_REQUEST))

// resume the generator with some dummy action
const mockAction = {user: '...', pass: '...'}
assert.deepEqual(
  iterator.next(mockAction).value, 
  call(request.post, '/login', mockAction)
)

// simulate an error result
const mockError = 'invalid user/password'
assert.deepEqual(
  iterator.throw(mockError).value, 
  put({ type: LOGIN_ERROR, error: mockError })
)

Lưu ý rằng chúng tôi đang chế nhạo kết quả cuộc gọi api bằng cách tiêm dữ liệu giả định vào nextphương thức của trình vòng lặp. Mocking data là cách đơn giản hơn so với chức năng mocking.

Điều thứ hai cần chú ý là cuộc gọi đến yield take(ACTION). Thunk được gọi bởi người tạo hành động trên mỗi hành động mới (ví dụ LOGIN_REQUEST). tức là các hành động liên tục được đẩy lên thunks và thunks không kiểm soát được thời điểm dừng xử lý các hành động đó.

Trong redux-saga, máy phát điện kéo hành động tiếp theo. tức là họ có quyền kiểm soát khi nào nên lắng nghe một số hành động, và khi nào thì không. Trong ví dụ trên, các hướng dẫn luồng được đặt bên trong một while(true)vòng lặp, do đó, nó sẽ lắng nghe từng hành động đến, phần nào bắt chước hành vi đẩy của thunk.

Phương pháp kéo cho phép thực hiện các luồng điều khiển phức tạp. Giả sử ví dụ chúng tôi muốn thêm các yêu cầu sau

  • Xử lý hành động người dùng ĐĂNG KÝ

  • khi đăng nhập thành công đầu tiên, máy chủ trả về mã thông báo sẽ hết hạn trong một số độ trễ được lưu trữ trong một expires_intrường. Chúng tôi sẽ phải làm mới ủy quyền trong nền trên mỗi expires_inmili giây

  • Hãy tính đến việc khi chờ kết quả của các cuộc gọi api (đăng nhập ban đầu hoặc làm mới), người dùng có thể đăng xuất ở giữa.

Làm thế nào bạn sẽ thực hiện điều đó với thunks; trong khi cũng cung cấp bảo hiểm thử nghiệm đầy đủ cho toàn bộ dòng chảy? Đây là cách nó có thể nhìn với Sagas:

function* authorize(credentials) {
  const token = yield call(api.authorize, credentials)
  yield put( login.success(token) )
  return token
}

function* authAndRefreshTokenOnExpiry(name, password) {
  let token = yield call(authorize, {name, password})
  while(true) {
    yield call(delay, token.expires_in)
    token = yield call(authorize, {token})
  }
}

function* watchAuth() {
  while(true) {
    try {
      const {name, password} = yield take(LOGIN_REQUEST)

      yield race([
        take(LOGOUT),
        call(authAndRefreshTokenOnExpiry, name, password)
      ])

      // user logged out, next while iteration will wait for the
      // next LOGIN_REQUEST action

    } catch(error) {
      yield put( login.error(error) )
    }
  }
}

Trong ví dụ trên, chúng tôi thể hiện yêu cầu đồng thời bằng cách sử dụng race. Nếu take(LOGOUT)chiến thắng cuộc đua (tức là người dùng đã nhấp vào nút Đăng xuất). Cuộc đua sẽ tự động hủy authAndRefreshTokenOnExpirynhiệm vụ nền. Và nếu cuộc gọi authAndRefreshTokenOnExpirybị chặn giữa call(authorize, {token})cuộc gọi, nó cũng sẽ bị hủy. Hủy bỏ truyền xuống dưới tự động.

Bạn có thể tìm thấy bản chạy thử của luồng trên


@yassine delaychức năng đến từ đâu? À, đã tìm thấy nó: github.com/yelouafi/redux-saga/blob/iêu
philk

122
Các redux-thunkcode đang khá dễ đọc và tự giải thích. Nhưng redux-sagasmột thực sự không đọc được, chủ yếu là do những động từ giống như chức năng: call, fork, take, put...
syg

11
@syg, tôi đồng ý rằng cuộc gọi, ngã ba, nhận và đặt có thể thân thiện hơn về mặt ngữ nghĩa. Tuy nhiên, chính những chức năng giống như động từ đó làm cho tất cả các tác dụng phụ có thể kiểm tra được.
Downhillski

3
@syg vẫn là một chức năng với các chức năng động từ kỳ lạ đó dễ đọc hơn một chức năng với chuỗi hứa hẹn sâu sắc
Yasser Sinjab

3
những động từ "kỳ lạ" đó cũng giúp bạn khái niệm hóa mối quan hệ của câu chuyện với những thông điệp phát sinh. bạn có thể lấy các loại tin nhắn ra khỏi redux - thường để kích hoạt lần lặp tiếp theo và bạn có thể đưa tin nhắn mới trở lại để phát kết quả của hiệu ứng phụ của bạn.
worc

104

Tôi sẽ thêm kinh nghiệm của mình bằng cách sử dụng saga trong hệ thống sản xuất cùng với câu trả lời khá kỹ lưỡng của tác giả thư viện.

Pro (sử dụng saga):

  • Khả năng kiểm tra. Rất dễ dàng để kiểm tra sagas khi call () trả về một đối tượng thuần túy. Kiểm tra thunks thường yêu cầu bạn bao gồm một mockStore trong bài kiểm tra của bạn.

  • redux-saga đi kèm với rất nhiều chức năng trợ giúp hữu ích về các nhiệm vụ. Dường như với tôi, khái niệm về saga là tạo ra một loại công cụ / luồng nền cho ứng dụng của bạn, hoạt động như một phần còn thiếu trong kiến ​​trúc redux phản ứng (actionCreators và bộ giảm tốc phải là các hàm thuần túy.) Dẫn đến điểm tiếp theo.

  • Sagas cung cấp nơi độc lập để xử lý tất cả các tác dụng phụ. Nó thường dễ sửa đổi và quản lý hơn các hành động thunk theo kinh nghiệm của tôi.

Con:

  • Cú pháp trình tạo.

  • Rất nhiều khái niệm để học hỏi.

  • API ổn định. Có vẻ như redux-saga vẫn đang thêm các tính năng (ví dụ: Kênh?) Và cộng đồng không lớn như vậy. Có một mối quan tâm nếu thư viện thực hiện cập nhật không tương thích ngược một ngày nào đó.


9
Chỉ muốn đưa ra một số nhận xét, người tạo hành động không cần phải là chức năng thuần túy, điều đã được chính Dan tuyên bố nhiều lần.
Marson Mao

14
Cho đến bây giờ, redux-sagas rất được khuyến khích vì việc sử dụng và cộng đồng đã mở rộng. Ngoài ra, API đã trở nên trưởng thành hơn. Xem xét loại bỏ Con cho API stabilitynhư một bản cập nhật để phản ánh tình hình hiện tại.
Denialos

1
saga có nhiều khởi đầu hơn thunk và cam kết cuối cùng của nó là sau thunk nữa
amorenew

2
Vâng, FWIW redux-saga hiện có 12k sao, redux-thunk có 8k
Brian Burns

3
Tôi sẽ thêm một thử thách khác về sagas, đó là sagas hoàn toàn tách rời khỏi hành động và người tạo hành động theo mặc định. Trong khi Thunks trực tiếp kết nối những người tạo hành động với các tác dụng phụ của họ, thì sagas lại khiến những người sáng tạo hành động tách biệt hoàn toàn với những người sagas lắng nghe họ. Điều này có lợi thế kỹ thuật, nhưng có thể làm cho mã khó theo dõi hơn và có thể làm mờ một số khái niệm đơn hướng.
theaceofthespade

33

Tôi chỉ muốn thêm một số nhận xét từ trải nghiệm cá nhân của tôi (sử dụng cả sagas và thunk):

Sagas là tuyệt vời để kiểm tra:

  • Bạn không cần phải giả lập các chức năng được bao bọc bằng các hiệu ứng
  • Do đó, các bài kiểm tra là sạch sẽ, dễ đọc và dễ viết
  • Khi sử dụng sagas, người tạo hành động chủ yếu trả về nghĩa đen của đối tượng đơn giản. Nó cũng dễ dàng hơn để kiểm tra và khẳng định không giống như lời hứa của thunk.

Sagas mạnh hơn. Tất cả những gì bạn có thể làm trong một người tạo hành động của một thunk bạn cũng có thể làm trong một câu chuyện, nhưng không phải ngược lại (hoặc ít nhất là không dễ dàng). Ví dụ:

  • chờ đợi một hành động / hành động được gửi đi ( take)
  • hủy thường xuyên hiện có ( cancel, takeLatest, race)
  • nhiều thói quen có thể lắng nghe những hành động tương tự ( take, takeEvery, ...)

Sagas cũng cung cấp các chức năng hữu ích khác, giúp khái quát một số mẫu ứng dụng phổ biến:

  • channels để nghe trên các nguồn sự kiện bên ngoài (ví dụ: websockets)
  • mô hình ngã ba ( fork, spawn)
  • van tiết lưu
  • ...

Sagas là công cụ tuyệt vời và mạnh mẽ. Tuy nhiên với sức mạnh đến trách nhiệm. Khi ứng dụng của bạn phát triển, bạn có thể dễ dàng bị mất bằng cách tìm ra ai đang chờ hành động được gửi đi, hoặc mọi thứ xảy ra khi một hành động nào đó được gửi đi. Mặt khác, thunk đơn giản và dễ lý luận hơn. Chọn cái này hay cái khác phụ thuộc vào nhiều khía cạnh như loại và quy mô của dự án, loại tác dụng phụ nào mà dự án của bạn phải xử lý hoặc ưu tiên nhóm dev. Trong mọi trường hợp chỉ cần giữ cho ứng dụng của bạn đơn giản và có thể dự đoán.


8

Chỉ là một số kinh nghiệm cá nhân:

  1. Đối với phong cách mã hóa và khả năng đọc, một trong những lợi thế quan trọng nhất của việc sử dụng redux-saga trong quá khứ là tránh địa ngục gọi lại trong redux-thunk - người ta không cần phải sử dụng nhiều lồng sau đó / bắt nữa. Nhưng bây giờ với sự phổ biến của async / await thunk, người ta cũng có thể viết mã async theo kiểu đồng bộ hóa khi sử dụng redux-thunk, có thể được coi là một cải tiến trong suy nghĩ redux.

  2. Người ta có thể cần phải viết mã soạn sẵn nhiều hơn khi sử dụng redux-saga, đặc biệt là trong Bản in. Ví dụ: nếu một người muốn thực hiện chức năng tìm nạp đồng bộ, việc xử lý dữ liệu và lỗi có thể được thực hiện trực tiếp trong một đơn vị thunk trong action.js với một hành động FETCH duy nhất. Nhưng trong redux-saga, người ta có thể cần xác định các hành động FETCH_START, FETCH_SUCCESS và FETCH_FAILURE và tất cả các kiểm tra loại liên quan của họ, bởi vì một trong những tính năng trong redux-saga là sử dụng loại cơ chế mã thông báo phong phú này để tạo hiệu ứng và hướng dẫn cửa hàng redux để thử nghiệm dễ dàng. Tất nhiên người ta có thể viết một saga mà không cần sử dụng những hành động này, nhưng điều đó sẽ làm cho nó tương tự như một thunk.

  3. Về mặt cấu trúc tập tin, redux-saga dường như rõ ràng hơn trong nhiều trường hợp. Người ta có thể dễ dàng tìm thấy một mã liên quan không đồng bộ trong mọi sagas.ts, nhưng trong redux-thunk, người ta sẽ cần phải nhìn thấy nó trong các hành động.

  4. Kiểm tra dễ dàng có thể là một tính năng có trọng số khác trong redux-saga. Điều này thực sự thuận tiện. Nhưng một điều cần được làm rõ là thử nghiệm cuộc gọi redux-saga của Cuộc gọi trực tuyến sẽ không thực hiện cuộc gọi API thực tế trong thử nghiệm, do đó, người ta sẽ cần chỉ định kết quả mẫu cho các bước có thể sử dụng sau cuộc gọi API. Do đó, trước khi viết bằng redux-saga, sẽ tốt hơn nếu lên kế hoạch cho một saga và sagas.spec.ts tương ứng của nó một cách chi tiết.

  5. Redux-saga cũng cung cấp nhiều tính năng nâng cao như chạy các tác vụ song song, trợ giúp đồng thời như TakeLatest / TakeEvery, fork / spawn, mạnh hơn nhiều so với thunks.

Tóm lại, cá nhân, tôi muốn nói: trong nhiều trường hợp bình thường và các ứng dụng cỡ nhỏ đến trung bình, hãy sử dụng redux-thunk theo phong cách async / await. Nó sẽ giúp bạn tiết kiệm nhiều mã / hành động / typedefs, và bạn không cần phải chuyển qua nhiều sagas.ts khác nhau và duy trì một cây sagas cụ thể. Nhưng nếu bạn đang phát triển một ứng dụng lớn với logic async phức tạp và nhu cầu về các tính năng như mô hình song song / song song hoặc có nhu cầu cao về thử nghiệm và bảo trì (đặc biệt là trong phát triển dựa trên thử nghiệm), redux-sagas có thể sẽ cứu mạng bạn .

Dù sao, redux-saga không khó khăn và phức tạp hơn bản thân redux và nó không có cái gọi là đường cong học tập dốc vì nó có các khái niệm và API cốt lõi được giới hạn tốt. Dành một lượng nhỏ thời gian để học redux-saga có thể mang lại lợi ích cho bạn một ngày nào đó trong tương lai.


5

Đã xem xét một vài dự án React / Redux quy mô lớn khác nhau theo kinh nghiệm của tôi Sagas cung cấp cho các nhà phát triển một cách viết mã có cấu trúc chặt chẽ hơn, dễ kiểm tra hơn và khó bị sai hơn.

Vâng, đó là một chút khôn ngoan để bắt đầu, nhưng hầu hết các nhà phát triển có đủ sự hiểu biết về nó trong một ngày. Tôi luôn nói với mọi người đừng lo lắng về những gìyield bắt đầu với và một khi bạn viết một vài bài kiểm tra, nó sẽ đến với bạn.

Tôi đã thấy một vài dự án trong đó thunks đã được xử lý như thể chúng là bộ điều khiển từ patten MVC và điều này nhanh chóng trở thành một mớ hỗn độn không thể nhầm lẫn.

Lời khuyên của tôi là sử dụng Sagas nơi bạn cần A kích hoạt công cụ loại B liên quan đến một sự kiện. Đối với bất kỳ điều gì có thể cắt ngang một số hành động, tôi thấy việc viết phần mềm trung gian của khách hàng sẽ đơn giản hơn và sử dụng thuộc tính meta của một hành động FSA để kích hoạt nó.


2

Thunk so với Sagas

Redux-ThunkRedux-Saga khác nhau theo một số cách quan trọng, cả hai đều là thư viện phần mềm trung gian cho Redux (phần mềm trung gian Redux là mã chặn các hành động đi vào cửa hàng thông qua phương thức Clark ()).

Một hành động có thể là bất cứ điều gì theo nghĩa đen, nhưng nếu bạn đang theo các thực tiễn tốt nhất, một hành động là một đối tượng javascript đơn giản với trường loại và các trường tải trọng, meta và lỗi tùy chọn. ví dụ

const loginRequest = {
    type: 'LOGIN_REQUEST',
    payload: {
        name: 'admin',
        password: '123',
    }, };

Redux-Thunk

Ngoài việc gửi các hành động tiêu chuẩn, Redux-Thunkphần mềm trung gian cho phép bạn gửi các chức năng đặc biệt, được gọi làthunks .

Thunks (trong Redux) thường có cấu trúc sau:

export const thunkName =
   parameters =>
        (dispatch, getState) => {
            // Your application logic goes here
        };

Nghĩa là, a thunklà một hàm (tùy chọn) nhận một số tham số và trả về một hàm khác. Hàm bên trong có một dispatch functionvà một getStatehàm - cả hai sẽ được cung cấp bởi Redux-Thunkphần mềm trung gian.

Redux-Saga

Redux-Sagamiddleware cho phép bạn thể hiện logic ứng dụng phức tạp như các hàm thuần túy được gọi là sagas. Các hàm thuần túy được mong muốn từ quan điểm kiểm tra vì chúng có thể dự đoán và lặp lại được, điều này làm cho chúng tương đối dễ kiểm tra.

Sagas được thực hiện thông qua các chức năng đặc biệt gọi là chức năng tạo. Đây là một tính năng mới của ES6 JavaScript. Về cơ bản, thực thi nhảy vào và ra khỏi một trình tạo ở mọi nơi bạn thấy một tuyên bố lợi suất. Hãy nghĩ về một yieldtuyên bố là làm cho trình tạo tạm dừng và trả về giá trị mang lại. Sau đó, người gọi có thể tiếp tục trình tạo tại câu lệnh sauyield .

Một hàm tạo là một định nghĩa như thế này. Lưu ý dấu hoa thị sau từ khóa chức năng.

function* mySaga() {
    // ...
}

Khi saga đăng nhập được đăng ký với Redux-Saga. Nhưng sau đó, yielddòng đầu tiên sẽ tạm dừng câu chuyện cho đến khi một hành động với kiểu'LOGIN_REQUEST' được gửi đến cửa hàng. Một khi điều đó xảy ra, thực thi sẽ tiếp tục.

Để biết thêm chi tiết xem bài viết này .


1

Một lưu ý nhanh. Máy phát điện có thể hủy, async / await - không. Vì vậy, đối với một ví dụ từ câu hỏi, nó không thực sự có ý nghĩa về những gì để chọn. Nhưng đối với các luồng phức tạp hơn đôi khi không có giải pháp nào tốt hơn là sử dụng máy phát điện.

Vì vậy, một ý tưởng khác có thể là sử dụng máy phát điện với redux-thunk, nhưng đối với tôi, nó có vẻ như cố gắng phát minh ra một chiếc xe đạp có bánh xe vuông.

Và tất nhiên, máy phát điện dễ kiểm tra hơn.


0

Đây là một dự án kết hợp các phần tốt nhất (ưu) của cả hai redux-sagaredux-thunk: bạn có thể xử lý tất cả các tác dụng phụ trên sagas trong khi nhận được lời hứa bằng dispatchinghành động tương ứng: https://github.com/diegohaz/redux-saga-thunk

class MyComponent extends React.Component {
  componentWillMount() {
    // `doSomething` dispatches an action which is handled by some saga
    this.props.doSomething().then((detail) => {
      console.log('Yaay!', detail)
    }).catch((error) => {
      console.log('Oops!', error)
    })
  }
}

1
sử dụng then()bên trong một thành phần React là chống lại mô hình. Bạn nên xử lý trạng thái đã thay đổi thay componentDidUpdatevì chờ đợi một lời hứa được giải quyết.

3
@ Maxincredible52 Điều đó không đúng với Kết xuất phía máy chủ.
Diego Haz

Theo kinh nghiệm của tôi, quan điểm của Max vẫn đúng với kết xuất phía máy chủ. Điều này có lẽ nên được xử lý ở đâu đó trong lớp định tuyến.
ThinkingInBits

3
@ Maxincredible52 tại sao nó chống lại mô hình, bạn đã đọc nó ở đâu? Tôi thường làm tương tự như @Diego Haz nhưng thực hiện nó trong thành phầnDidMount (theo tài liệu React, các cuộc gọi mạng nên được thực hiện ở đó) vì vậy chúng tôi cócomponentDidlMount() { this.props.doSomething().then((detail) => { this.setState({isReady: true})} }
user3711421

0

Một cách dễ dàng hơn là sử dụng redux-auto .

từ sự thuyết phục

redux-auto đã khắc phục sự cố không đồng bộ này chỉ bằng cách cho phép bạn tạo chức năng "hành động" trả lại lời hứa. Để đi kèm với logic hành động chức năng "mặc định" của bạn.

  1. Không cần các phần mềm trung gian không đồng bộ Redux khác. ví dụ như thunk, hứa-trung gian, saga
  2. Dễ dàng cho phép bạn chuyển lời hứa thành redux và quản lý nó cho bạn
  3. Cho phép bạn đồng định vị các cuộc gọi dịch vụ bên ngoài với nơi chúng sẽ được chuyển đổi
  4. Đặt tên tệp "init.js" sẽ gọi nó một lần khi bắt đầu ứng dụng. Điều này tốt cho việc tải dữ liệu từ máy chủ khi bắt đầu

Ý tưởng là để mỗi hành động trong một tập tin cụ thể . đồng định vị cuộc gọi máy chủ trong tệp với các chức năng giảm tốc cho "đang chờ xử lý", "đã hoàn thành" và "bị từ chối". Điều này làm cho việc xử lý hứa hẹn rất dễ dàng.

Nó cũng tự động đính kèm một đối tượng trợ giúp (được gọi là "async") vào nguyên mẫu của trạng thái của bạn, cho phép bạn theo dõi trong giao diện người dùng của mình, các chuyển đổi được yêu cầu.


2
Tôi đã thực hiện +1 ngay cả câu trả lời không liên quan vì các giải pháp khác nhau cũng nên được xem xét
amorenew

12
Tôi nghĩ rằng - đó là vì anh ấy đã không tiết lộ anh ấy là tác giả của dự án
jreptak
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.