异步/等待等待承诺解决

时间:2018-02-16 02:04:25

标签: javascript reactjs asynchronous redux

似乎我对await的使用并不像我理解的那样。

我认为async函数和await关键字可用于返回promise的调用(例如navigator.mediaDevices.getUserMedia),它会暂停函数执行(如生成器函数)直到promise解决,然后它将继续使用该函数。

即使我正在等待电话,它立即返回,我的控制台日志也发生了故障。特别是控制台日志以" reducer"开头。出现在" getter"之前的控制台中,当它应该是相反的方式/与我认为堆栈跟踪应该如何运行相反。

谁能告诉我这里发生了什么?

异步辅助函数getter:

const getLocalStream = async () => {
  try {
    const localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    console.log('getter localStream', localStream);
    console.log('about to return')
    return localStream;
  }
  catch (err) {
    console.error(err);
  }
}

export default getLocalStream;

Reducer / store:

import getLocalStream from './getLocalStream';

const reducer = (state = {}, action) => {
  switch (action.type) {
    case 'SEND_CALL': {
      const { id } = action;
      const localStream =  getLocalStream();
      console.log('reducer localStream', localStream);
      const call = state.peer.call(id, localStream);
      return { ...state, call };
    }
    default: 
      return state;
  }
};

控制台:

reducer localStream Promise {<pending>}
Uncaught TypeError: Failed to execute 'addStream' on 'RTCPeerConnection': parameter 1 is not of type 'MediaStream'
getter localStream MediaStream {id: "B6Foz1jheGvnMqjiqC4PFoOvUVahF04zigzm", active: true, onaddtrack: null, onremovetrack: null, onactive: null, …}
about to return

3 个答案:

答案 0 :(得分:2)

使用redx-thunk。由于您的reducer必须返回一个新状态,因此您无法在reducer中执行异步操作。

您可以在中间件中进行异步操作,这样您就可以自己编写中间件或使用redux-thunk。

如果您发送一个函数动作,那么thunk将使用AdapterNotification.javapackage com.myapp.adapter; import android.content.Context; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import com.material.nereeducation.R; import com.material.nereeducation.helper.AlphabetColor; import com.material.nereeducation.model.Notification; import com.material.nereeducation.utils.Tools; import java.util.ArrayList; import java.util.Date; import java.util.List; public class AdapterNotification extends RecyclerView.Adapter<AdapterNotification.ViewHolder> { private Context ctx; private List<Notification> items; private OnClickListener onClickListener = null; private SparseBooleanArray selected_items; private int current_selected_idx = -1; private AlphabetColor alphabetColor; public void setOnClickListener(OnClickListener onClickListener) { this.onClickListener = onClickListener; } public class ViewHolder extends RecyclerView.ViewHolder { public TextView from, title, message, date, image_letter; public ImageView image; public RelativeLayout lyt_checked, lyt_image; public View lyt_parent; public ViewHolder(View view) { super(view); from = view.findViewById(R.id.from); title = view.findViewById(R.id.title); message = view.findViewById(R.id.message); date = view.findViewById(R.id.date); image_letter = view.findViewById(R.id.image_letter); image = view.findViewById(R.id.image); lyt_checked = view.findViewById(R.id.lyt_checked); lyt_image = view.findViewById(R.id.lyt_image); lyt_parent = view.findViewById(R.id.lyt_parent); } } public AdapterNotification(Context mContext, List<Notification> items) { this.ctx = mContext; this.items = items; selected_items = new SparseBooleanArray(); alphabetColor = new AlphabetColor(mContext); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_notification, parent, false); return new ViewHolder(itemView); } @Override public void onBindViewHolder(final ViewHolder holder, final int position) { final Notification notification = items.get(position); // displaying text view data System.out.println("sender type:"+notification.sender_type); Character firstLetter; if(notification.sender_type.equals("1")) //Admin { String admin = ctx.getString(R.string.admin_name); holder.from.setText(admin); firstLetter = admin.substring(0, 1).charAt(0); holder.image_letter.setText(String.valueOf(firstLetter)); }else { holder.from.setText(notification.senderName); firstLetter = notification.senderName.substring(0, 1).charAt(0); holder.image_letter.setText(String.valueOf(firstLetter)); } if(notification.status.equals("unread")) { holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); } holder.title.setText(notification.title); holder.message.setText(notification.message); holder.date.setText(getDate(Long.parseLong(notification.date))); holder.lyt_parent.setActivated(selected_items.get(position, false)); holder.lyt_parent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (onClickListener == null) return; onClickListener.onItemClick(v, notification, position); } }); holder.lyt_parent.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (onClickListener == null) return false; onClickListener.onItemLongClick(v, notification, position); return true; } }); toggleCheckedIcon(holder, position); displayImage(holder, notification, firstLetter); } private void displayImage(ViewHolder holder, Notification notification, Character firstLetter) { if (notification.image != null) { Tools.displayImageRound(ctx, holder.image, notification.image); holder.image.setColorFilter(null); holder.image_letter.setVisibility(View.GONE); } else { holder.image.setImageResource(R.drawable.shape_circle); holder.image.setColorFilter(alphabetColor.getColorByAlphabet(firstLetter), PorterDuff.Mode.MULTIPLY); holder.image_letter.setVisibility(View.VISIBLE); } } private String getDate(long time) { Date date = new Date(); long currentTime = date.getTime(); String result = (String) DateUtils.getRelativeTimeSpanString(time, currentTime, 0); return result; } private void toggleCheckedIcon(ViewHolder holder, int position) { if (selected_items.get(position, false)) { holder.lyt_image.setVisibility(View.GONE); holder.lyt_checked.setVisibility(View.VISIBLE); if (current_selected_idx == position) resetCurrentIndex(); } else { holder.lyt_checked.setVisibility(View.GONE); holder.lyt_image.setVisibility(View.VISIBLE); if (current_selected_idx == position) resetCurrentIndex(); } } public Notification getItem(int position) { return items.get(position); } @Override public int getItemCount() { return items.size(); } public void toggleSelection(int pos) { current_selected_idx = pos; if (selected_items.get(pos, false)) { selected_items.delete(pos); } else { selected_items.put(pos, true); } notifyItemChanged(pos); } public void clearSelections() { selected_items.clear(); notifyDataSetChanged(); } public int getSelectedItemCount() { return selected_items.size(); } public List<Integer> getSelectedItems() { List<Integer> items = new ArrayList<>(selected_items.size()); for (int i = 0; i < selected_items.size(); i++) { items.add(selected_items.keyAt(i)); } return items; } public void removeData(int position) { items.remove(position); resetCurrentIndex(); } private void resetCurrentIndex() { current_selected_idx = -1; } public interface OnClickListener { void onItemClick(View view, Notification obj, int pos); void onItemLongClick(View view, Notification obj, int pos); } } 函数执行该函数。

dispatch

Thunk将简化异步中间件或需要分派多个操作的操作。

如何解释redux的工作方式以及中间件如何工作here它正在调用reducer“应用程序处理函数”,因为我将它作为事件存储而不是针对redux特定的。

为什么redux不接受promises作为状态并且只是在结算时设置状态的原因可以找到here。当一个待处理的过滤器请求被来自用户的较新请求替换时,挂起的过滤器将拒绝,这应该发生什么但是redux如何知道该承诺应该拒绝?因此,如果我们必须解决那么,当旧的待处理请求解决时,我们如何告诉redux不要设置状态?这些问题基本上可以通过reducer不返回promise并在中间件中处理它来解决。

答案 1 :(得分:1)

您需要await调用减速器中的async功能。

现在,你打电话给它,但绝不等待它完成。

答案 2 :(得分:1)

您也需要在async/await函数中使用reducer,否则getLocalStream()将只返回promise个实例。

这是因为,根据docs

  

当调用异步函数时,它返回一个Promise。当异步函数返回一个值时,将使用返回的值解析Promise。当异步函数抛出异常或某个值时,将使用抛出的值拒绝Promise。

     

异步函数可以包含一个等待表达式,它会暂停   执行异步函数并等待传递的Promise   解析,然后恢复异步函数的执行和   返回已解析的值。

const reducer = async (state = {}, action) => { //HERE
  switch (action.type) {
    case 'SEND_CALL': {
      const { id } = action;
      const localStream =  await getLocalStream(); //HERE
      console.log('reducer localStream', localStream);
      const call = state.peer.call(id, localStream);
      return { ...state, call };
    }
    default: 
      return state;
  }
};