【问题标题】:Returning status values after using Promise for onload and onerror使用 Promise 进行 onload 和 onerror 后返回状态值
【发布时间】:2020-08-18 15:54:33
【问题描述】:

我正在尝试查看页面/img 是否使用 javascript onload 和 onerror 成功加载。我正在尝试读取状态变量,但是当我分配变量来读取状态时无法这样做。 我正在尝试使用提供的可能答案中概述的承诺,但仍然有些困惑。


const validateInput = (input) => {
  const errors = {};
  ... 

    if(!(isImgURlValid(input)))
    {
      errors = `wrong image'` 
    }
    ... 
  return errors;

const isImgURlValid = (path) => {
  let img = document.createElement('img');
  img.src = path;  
  let valid
 const promise = new Promise(resolve => {
    const img = new Image();
    img.onload = () => resolve({path, "status": 'ok'});
    img.onerror = () => resolve({path, "status": 'error'});
     img.src = path;
});
promise.then(function(val) { 
  console.log(val); 
  valid = val.status
}); 
console.log (valid)
}

//when I use async, my render functions no long render the errors properly
export const renderImgUrlInput = ({ input, label, type, size, required, meta: { touched, error } }) => (
  <div className={
    cs('form-group', size, {
      'has-error': touched && error,
      'required-input' : required
    })
  }>
    <label className="control-label" htmlFor={input.name}>{label}</label>
    <input {...input} placeholder={required ? 'Required' : ''} className="form-control" /> 
    {touched && error &&
      <span className="help-block">{error}</span>
    }
    {touched && !error &&
      <h1 className="help-block">{error} 'Image worked'</h1>
    }
  </div>
)

【问题讨论】:

  • 这就是我阅读的文档并继续使用承诺,但仍然对此有些困惑。
  • 您只有在解析调用成功完成后才能访问valid,@LisaDane,在那之前,valid 将是未定义的,因为promise 尚未解决或拒绝。公平地说,您的 isImgURlValid 应该返回承诺而不是未定义,然后该函数的使用者需要使用 then/catch 链来验证它
  • 我明白你在说什么。我编辑了我的代码并添加了更多部分以在上下文中更多地显示它。那么我怎样才能将值提升到我的函数 isImgURLvalid
  • @LisaDane 我更新了我的答案以反映这一点,但这对你没有帮助,你必须在代码中的某个时间处理异步调用的承诺或结果,所以尽早处理

标签: javascript ecmascript-6 promise onload


【解决方案1】:

const isImgURLValid = (path) => {
    return new Promise((resolve, reject) => {
        const img = document.createElement("img");
        img.src = path;
        img.onload = resolve;
        img.onerror = reject;
        img.src = path;
        document.body.appendChild(img);
    });
};

isImgURLValid("https://www.gravatar.com/avatar/206601a888686677c4a74c89d9a2920f?s=48&d=identicon&r=PG")
    .then(() => console.log("Path is valid"))
    .catch(() => console.error("Path isn't valid"))

【讨论】:

  • 谢谢。这看起来很清楚。我在使用 isImgURLValid 作为检查的地方编辑了我的代码。我很困惑如何将路径是否有效地冒泡到我的验证函数中。
  • @LisaDane 您无法以同步方式从 Promise 中获得价值。请阅读此stackoverflow.com/questions/37220554/…
【解决方案2】:

您应该将您创建的 Promise 从 isImgURlValid 返回给调用者。然后调用者可以等待 promise 解析并使用解析的值来查看提供的图像源是否有效。

这是一个受问题代码启发的示例。可以在输入框中输入图片源,然后按Enter触发事件。

const isImgURlValid = (path) => { 
  return new Promise(resolve => {    
    const img = new Image()
    img.src = path;
    img.onload = () => resolve(true);
    img.onerror = () => resolve(false);
    
    // img starts loading src when added to the DOM
    document.body.append(img);
    document.body.removeChild(img);
  });
};

const validateInput = async (input) => {
  const errors = {};
  if (!await isImgURlValid(input)) {
    errors.url = "invalid";
  }
  return errors;
};

document.getElementById("input").addEventListener("change", ({target}) => {
  validateInput(target.value).then(console.log);
});
&lt;input id="input" type="text" /&gt;

【讨论】:

  • 我非常喜欢这个。它非常清楚,尤其是因为我是新的承诺。
  • 实际上这个答案很好,但不幸的是,当我使我的验证函数异步时,它会抛出其他所有问题。我将添加代码以向您展示我的意思。
  • @LisaDane 这就是我在回答中指出的一点,在某个时间,您必须处理返回的错误,因此必须处理。您可以将此答案标记为已回答,并开始一个新问题来处理错误,而不是将这个问题变成变色龙
  • @LisaDane 我不太清楚这两个初始函数和渲染函数是如何相互连接的。在 React 中,我会说您在验证 then 回调中执行以下操作;将生成的验证数据存储到组件状态中。这会导致重新渲染,然后您可以在其中使用数据或将其进一步向下传递给其他组件。
  • handleClick = (event) =&gt; asyncFn(event.target).then(data =&gt; setData(data)) 然后在您的渲染结果中{data &amp;&amp; &lt;div&gt; do stuff with the async data &lt;/div&gt;} 或将data 设置为默认值,这样就不需要data &amp;&amp;
【解决方案3】:

我猜你可能对 promises 有点陌生,表明你已经阅读了建议的副本,但你可以通过以下方式重新制定你的代码

const isImgUrlValid = (path) => {
  return new Promise( (resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve({path, "status": 'ok'});
    img.onerror = () => reject({path, "status": 'error'});
     img.src = path;
  });
};

// when it's found, resolve got called and we know it succeeded
isImgUrlValid('https://www.gravatar.com/avatar/153828e74e3fb5f7aeb19a28a78a378a?s=32&d=identicon&r=PG&f=1').then( status => console.log('image found') );

// when it's not found reject was called, and we need to catch it
isImgUrlValid('invalid_uri').then( _ => console.log('I will never be called') ).catch( err => console.log('no image found') );

这将使用 resolve(成功)和 reject(失败)来使用 promise 的正常工作流程。

通过返回承诺,任何消费者都可以使用thencatch 链来处理成功或失败

假设你想在一个函数中使用上面的代码,然后它会发生一些变化,你不能真正同步检查这个,除非调用者是一个async函数,在这种情况下你可以这样做:

const validateInput = async () => {
  let isValidImage = false;
  try {
   isValidImage = await isImgUrlValid( path );
  } catch (ex) {
    // not a correct image
    
  }
};

但这对你没有帮助,因为现在 validateInput 隐式返回一个承诺,所以你必须把它当作一个承诺来处理。

【讨论】:

  • 我不太明白你的最后一句话。到目前为止,您的意思是什么对我没有帮助。
  • @LisaDane 它只是意味着此时您还必须处理来自 validateInput 函数的承诺,因此如果您在某个时间点或序列中的更早或更晚处理承诺,您将必须处理它
猜你喜欢
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-21
  • 2012-03-14
  • 2020-12-30
相关资源
最近更新 更多